1 // interface.c
2 // LiVES
3 // (c) G. Finch 2003 - 2020 <salsaman+lives@gmail.com>
4 // Released under the GNU GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 #include "main.h"
8 #include "callbacks.h"
9 #include "interface.h"
10 #include "paramwindow.h"
11 #include "merge.h"
12 #include "resample.h"
13 #include "startup.h"
14 #include "omc-learn.h" // for OSC_NOTIFY mapping
15 
16 // functions called in multitrack.c
17 extern void multitrack_preview_clicked(LiVESButton *, livespointer user_data);
18 extern void mt_change_disp_tracks_ok(LiVESButton *, livespointer user_data);
19 
20 static void dsu_fill_details(LiVESWidget *widget, livespointer data);
21 static void qslider_changed(LiVESWidget *slid, livespointer data);
22 
add_suffix_check(LiVESBox * box,const char * ext)23 void add_suffix_check(LiVESBox *box, const char *ext) {
24   char *ltext;
25 
26   LiVESWidget *checkbutton;
27 
28   if (!ext) ltext = (_("Let LiVES set the _file extension"));
29   else ltext = lives_strdup_printf(_("Let LiVES set the _file extension (.%s)"), ext);
30   checkbutton = lives_standard_check_button_new(ltext, mainw->fx1_bool, box, NULL);
31   lives_free(ltext);
32   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
33                                   LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->fx1_bool);
34 }
35 
36 
add_deinterlace_checkbox(LiVESBox * for_deint)37 static LiVESWidget *add_deinterlace_checkbox(LiVESBox *for_deint) {
38   char *tmp, *tmp2;
39   LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
40   LiVESWidget *checkbutton = lives_standard_check_button_new((tmp = (_("Apply _Deinterlace"))), mainw->open_deint,
41                              LIVES_BOX(hbox),
42                              (tmp2 = (_("If this is set, frames will be deinterlaced as they are imported."))));
43   lives_free(tmp); lives_free(tmp2);
44 
45   if (LIVES_IS_HBOX(for_deint)) {
46     LiVESWidget *filler;
47     lives_box_pack_top(for_deint, hbox, FALSE, FALSE, widget_opts.packing_width);
48     filler = add_fill_to_box(LIVES_BOX(for_deint));
49     if (filler) lives_box_reorder_child(for_deint, filler, 1);
50   } else lives_box_pack_start(for_deint, hbox, FALSE, FALSE, widget_opts.packing_height);
51 
52   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
53                                   LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->open_deint);
54 
55   lives_widget_show_all(LIVES_WIDGET(for_deint));
56 
57   return hbox;
58 }
59 
60 
pv_sel_changed(LiVESFileChooser * chooser,livespointer user_data)61 static void pv_sel_changed(LiVESFileChooser *chooser, livespointer user_data) {
62   LiVESSList *slist;
63   LiVESWidget *pbutton = (LiVESWidget *)user_data;
64   if (!LIVES_IS_FILE_CHOOSER(chooser)) return;
65   slist = lives_file_chooser_get_filenames(chooser);
66   end_fs_preview();
67 
68   if (!slist || !slist->data || lives_slist_length(slist) > 1 ||
69       !(lives_file_test((char *)lives_slist_nth_data(slist, 0), LIVES_FILE_TEST_IS_REGULAR))) {
70     lives_widget_set_sensitive(pbutton, FALSE);
71   } else lives_widget_set_sensitive(pbutton, TRUE);
72 
73   lives_slist_free_all(&slist);
74 }
75 
76 
show_playbar_labels(int clipno)77 void show_playbar_labels(int clipno) {
78   lives_clip_t *sfile = mainw->files[clipno];
79   char *tmp, *tmpch;
80   char *str_video = (_("Video")), *str_opening;
81   boolean hhr, hvb, hla, hra;
82 
83   lives_label_set_text(LIVES_LABEL(mainw->vidbar), str_video);
84   tmp = get_achannel_name(2, 0);
85   lives_label_set_text(LIVES_LABEL(mainw->laudbar), tmp);
86   lives_free(tmp);
87   tmp = get_achannel_name(2, 1);
88   lives_label_set_text(LIVES_LABEL(mainw->raudbar), tmp);
89   lives_free(tmp);
90 
91   tmp = (_("(No video)"));
92 
93   if (palette->style & STYLE_1) {
94     hhr = hvb = hra = TRUE;
95     hla = FALSE;
96   } else {
97     hhr = hvb = hla = hra = FALSE;
98   }
99 
100   if (!IS_VALID_CLIP(clipno)) {
101     lives_label_set_text(LIVES_LABEL(mainw->vidbar), tmp);
102     lives_free(tmp);
103 
104     lives_free(str_video);
105     hhr = hvb = hla = hra = TRUE;
106     goto showhide;
107   }
108 
109   str_opening = (_("[opening...]"));
110 
111   if (CLIP_HAS_VIDEO(clipno)) {
112     if (sfile->opening_loc || (sfile->frames == 123456789 && sfile->opening)) {
113       lives_free(tmp);
114       tmp = lives_strdup_printf(_("%s %s"), str_video, str_opening);
115     } else {
116       if (sfile->fps > 0.) {
117         sfile->video_time = sfile->frames / sfile->fps;
118       }
119       if (sfile->video_time > 0.) {
120         lives_free(tmp);
121         tmp = lives_strdup_printf(_("%s [%.2f sec]"), str_video, sfile->video_time);
122       } else {
123         if (sfile->video_time <= 0. && sfile->frames > 0) {
124           lives_free(tmp);
125           tmp = (_("(Undefined)"));
126         }
127       }
128     }
129     lives_label_set_text(LIVES_LABEL(mainw->vidbar), tmp);
130     lives_free(tmp);
131 
132     hhr = hvb = FALSE;
133   }
134 
135   lives_free(str_video);
136 
137   if (!CLIP_HAS_AUDIO(clipno)) {
138     tmp = (_("(No audio)"));
139   } else {
140     hhr = FALSE;
141 
142     tmpch = get_achannel_name(sfile->achans, 0);
143     if (sfile->opening_audio) {
144       tmp = lives_strdup_printf(_("%s %s"), tmpch, str_opening);
145     } else {
146       tmp = lives_strdup_printf(_("%s [%.2f sec]"), tmpch, sfile->laudio_time);
147     }
148     lives_free(tmpch);
149   }
150 
151   lives_label_set_text(LIVES_LABEL(mainw->laudbar), tmp);
152   lives_free(tmp);
153 
154   if (sfile->achans > 1) {
155     tmpch = get_achannel_name(sfile->achans, 1);
156     if (sfile->opening_audio) {
157       tmp = lives_strdup_printf(_("%s %s"), tmpch, str_opening);
158     } else {
159       tmp = lives_strdup_printf(_("%s [%.2f sec]"), tmpch, sfile->raudio_time);
160     }
161     lives_free(tmpch);
162     lives_label_set_text(LIVES_LABEL(mainw->raudbar), tmp);
163     lives_free(tmp);
164     hra = FALSE;
165   }
166 
167   lives_free(str_opening);
168 
169 showhide:
170   if (!hhr && !lives_widget_is_visible(mainw->hruler)) lives_widget_show(mainw->hruler);
171   else if (hhr && lives_widget_is_visible(mainw->hruler)) lives_widget_hide(mainw->hruler);
172   if (!hvb && !lives_widget_is_visible(mainw->vidbar)) lives_widget_show(mainw->vidbar);
173   else if (hvb && lives_widget_is_visible(mainw->vidbar)) lives_widget_hide(mainw->vidbar);
174   if (!hla && !lives_widget_is_visible(mainw->laudbar)) lives_widget_show(mainw->laudbar);
175   else if (hla && lives_widget_is_visible(mainw->laudbar)) lives_widget_hide(mainw->laudbar);
176   if (!hra && !lives_widget_is_visible(mainw->raudbar)) lives_widget_show(mainw->raudbar);
177   else if (hra && lives_widget_is_visible(mainw->raudbar)) lives_widget_hide(mainw->raudbar);
178 }
179 
180 
clear_tbar_bgs(int posx,int posy,int width,int height,int which)181 void clear_tbar_bgs(int posx, int posy, int width, int height, int which) {
182   // empirically we need to draw wider
183   posx -= OVERDRAW_MARGIN;
184   if (width > 0) width += OVERDRAW_MARGIN;
185 
186   if (posx < 0) posx = 0;
187   if (posy < 0) posy = 0;
188 
189   if (which == 0 || which == 2) {
190     if (mainw->laudio_drawable) {
191       clear_widget_bg_area(mainw->laudio_draw, mainw->laudio_drawable, posx, posy, width, height);
192     }
193   }
194 
195   if (which == 0 || which == 3) {
196     if (mainw->raudio_drawable) {
197       clear_widget_bg_area(mainw->raudio_draw, mainw->raudio_drawable, posx, posy, width, height);
198     }
199   }
200 
201   if (which == 0 || which == 1) {
202     clear_widget_bg_area(mainw->video_draw, mainw->video_drawable, posx, posy, width, height);
203   }
204 }
205 
206 
lives_ce_update_timeline(int frame,double x)207 double lives_ce_update_timeline(int frame, double x) {
208   // update clip editor timeline
209   // sets real_pointer_time and pointer_time
210   // if frame == 0 then x must be a time value
211 
212   // returns the pointer time (quantised to frame)
213 
214   static int last_current_file = -1;
215 
216   if (!prefs->show_gui) return 0.;
217 
218   if (lives_widget_get_allocation_width(mainw->vidbar) <= 0) {
219     return 0.;
220   }
221 
222   if (!CURRENT_CLIP_IS_VALID) {
223     if (!prefs->hide_framebar) {
224       lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), "");
225       lives_widget_queue_draw_if_visible(mainw->framecounter);
226     }
227     clear_tbar_bgs(0, 0, 0, 0, 0);
228     show_playbar_labels(-1);
229     return -1.;
230   }
231 
232   if (x < 0.) x = 0.;
233 
234   if (frame == 0) frame = calc_frame_from_time4(mainw->current_file, x);
235 
236   x = calc_time_from_frame(mainw->current_file, frame);
237   if (x > CLIP_TOTAL_TIME(mainw->current_file)) x = CLIP_TOTAL_TIME(mainw->current_file);
238   cfile->real_pointer_time = x;
239 
240   if (cfile->frames > 0 && frame > cfile->frames) frame = cfile->frames;
241   x = calc_time_from_frame(mainw->current_file, frame);
242   cfile->pointer_time = x;
243 
244   cfile->frameno = cfile->last_frameno = frame;
245   if (cfile->achans) {
246     cfile->aseek_pos = (off64_t)((double)(cfile->real_pointer_time * cfile->arate) * cfile->achans *
247                                  (cfile->asampsize / 8));
248     if (cfile->aseek_pos > cfile->afilesize) cfile->aseek_pos = 0.;
249   }
250 
251 #ifndef ENABLE_GIW_3
252   lives_ruler_set_value(LIVES_RULER(mainw->hruler), x);
253   lives_widget_queue_draw_if_visible(mainw->hruler);
254 #endif
255 
256   if (prefs->show_gui && !prefs->hide_framebar && cfile->frames > 0) {
257     char *framecount;
258     if (cfile->frames > 0) framecount = lives_strdup_printf("%9d / %d", frame, cfile->frames);
259     else framecount = lives_strdup_printf("%9d", frame);
260     lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
261     lives_freep((void **)&framecount);
262     //lives_widget_queue_draw_if_visible(mainw->framecounter);
263   }
264 
265   if (!LIVES_IS_PLAYING && mainw->play_window && cfile->is_loaded && !mainw->multitrack) {
266     if (mainw->prv_link == PRV_PTR && mainw->preview_frame != frame) {
267       if (cfile->frames > 0) {
268         cfile->frameno = frame;
269         load_preview_image(FALSE);
270       }
271     }
272   }
273 
274   if (mainw->is_ready && !LIVES_IS_PLAYING && !prefs->hide_framebar && mainw->current_file != last_current_file) {
275     lives_signal_handler_block(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
276     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->pb_fps);
277     lives_signal_handler_unblock(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
278   }
279 
280   show_playbar_labels(mainw->current_file);
281   redraw_timeline(mainw->current_file);
282 
283   last_current_file = mainw->current_file;
284   return cfile->pointer_time;
285 }
286 
287 
update_timer_bars(int posx,int posy,int width,int height,int which)288 void update_timer_bars(int posx, int posy, int width, int height, int which) {
289   // update the on-screen timer bars,
290   // and if we are not playing,
291   // get play times for video, audio channels, and total (longest) time
292 
293   // refresh = reread audio waveforms
294 
295   // which 0 = all, 1 = vidbar, 2 = laudbar, 3 = raudbar
296 
297   lives_painter_t *cr = NULL;
298   char *filename;
299 
300   double allocwidth;
301   double atime;
302 
303   double y = 0., scalex;
304 
305   int start;
306   int offset_left = 0;
307   int offset_right = 0;
308   int offset_end;
309   int lpos = -9999, pos;
310 
311   int current_file = mainw->current_file;
312   int xwidth, zwidth;
313   int afd = -1;
314   int bar_height;
315 
316   register int i;
317 
318   if (CURRENT_CLIP_IS_VALID && cfile->cb_src != -1) mainw->current_file = cfile->cb_src;
319 
320   if (!CURRENT_CLIP_IS_VALID || mainw->foreign || mainw->multitrack || mainw->recoverable_layout) {
321     mainw->current_file = current_file;
322     return;
323   }
324 
325   if (!LIVES_IS_PLAYING) {
326     get_total_time(cfile);
327   }
328 
329   if (!mainw->is_ready || !prefs->show_gui) {
330     mainw->current_file = current_file;
331     return;
332   }
333 
334   // draw timer bars
335   // first the background
336   clear_tbar_bgs(posx, posy, width, height, which);
337 
338   // empirically we need to draw wider
339   posx -= OVERDRAW_MARGIN;
340   if (width > 0) width += OVERDRAW_MARGIN;
341   if (posx < 0) posx = 0;
342   if (posy < 0) posy = 0;
343 
344   if (cfile->frames > 0 && mainw->video_drawable && (which == 0 || which == 1)) {
345     bar_height = CE_VIDBAR_HEIGHT;
346     allocwidth = lives_widget_get_allocation_width(mainw->video_draw);
347     scalex = (double)allocwidth / CURRENT_CLIP_TOTAL_TIME;
348 
349     offset_left = ROUND_I((double)(cfile->start - 1.) / cfile->fps * scalex);
350     offset_right = ROUND_I((double)(cfile->end) / cfile->fps * scalex);
351 
352     cr = lives_painter_create_from_surface(mainw->video_drawable);
353     xwidth = UTIL_CLAMP(width, allocwidth);
354 
355     if (offset_left > posx) {
356       // unselected
357       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
358       lives_painter_rectangle(cr, posx, 0,
359                               NORMAL_CLAMP(offset_left - posx, xwidth),
360                               bar_height);
361       lives_painter_fill(cr);
362     }
363 
364     if (offset_right > posx) {
365       if (offset_left < posx) offset_left = posx;
366       if (offset_right > posx + xwidth) offset_right = posx + xwidth;
367       // selected
368       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_sel);
369       lives_painter_rectangle(cr, offset_left, 0, offset_right - offset_left,
370                               bar_height);
371       lives_painter_fill(cr);
372     }
373 
374     if (offset_right < posx + xwidth) {
375       if (posx > offset_right) offset_right = posx;
376       zwidth = ROUND_I(cfile->video_time * scalex) - offset_right;
377       if (posx < offset_right) xwidth -= offset_right - posx;
378       zwidth = NORMAL_CLAMP(zwidth, xwidth);
379       // unselected
380       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
381       lives_painter_rectangle(cr, offset_right, 0, zwidth, bar_height);
382       lives_painter_fill(cr);
383     }
384     lives_painter_destroy(cr);
385   }
386 
387   bar_height = CE_AUDBAR_HEIGHT / 2.;
388 
389   if (cfile->achans > 0 && mainw->laudio_drawable && (which == 0 || which == 2)) {
390     allocwidth = lives_widget_get_allocation_width(mainw->laudio_draw);
391     scalex = (double)allocwidth / CURRENT_CLIP_TOTAL_TIME;
392     offset_left = ROUND_I((double)(cfile->start - 1.) / cfile->fps * scalex);
393     offset_right = ROUND_I((double)(cfile->end) / cfile->fps * scalex);
394     offset_end = ROUND_I(cfile->laudio_time * scalex);
395 
396     if (!cfile->audio_waveform) {
397       cfile->audio_waveform = (float **)lives_calloc(cfile->achans, sizeof(float *));
398       cfile->aw_sizes = (size_t *)lives_calloc(cfile->achans, sizeof(size_t));
399     }
400 
401     start = offset_end;
402     if (!cfile->audio_waveform[0]) {
403       // re-read the audio
404       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(mainw->laudio_draw), "drawn", LIVES_INT_TO_POINTER(0)); // force redrawing
405       cfile->audio_waveform[0] = (float *)lives_calloc((int)offset_end, sizeof(float));
406       start = cfile->aw_sizes[0] = 0;
407     } else if (cfile->aw_sizes[0] != offset_end) {
408       start = 0;
409       cfile->audio_waveform[0] = (float *)lives_realloc(cfile->audio_waveform[0], (int)offset_end * sizeof(float));
410     }
411 
412     if (cfile->audio_waveform[0]) {
413       if (start != offset_end) {
414         cfile->aw_sizes[0] = offset_end;
415         filename = lives_get_audio_file_name(mainw->current_file);
416         afd = lives_open_buffered_rdonly(filename);
417         lives_free(filename);
418 
419         for (i = start; i < offset_end; i++) {
420           if (afd == -1) {
421             THREADVAR(read_failed) = -2;
422             return;
423           }
424           atime = (double)i / scalex;
425           cfile->audio_waveform[0][i] = cfile->vol
426                                         * get_float_audio_val_at_time(mainw->current_file, afd, atime, 0, cfile->achans) * 2.;
427         }
428         lives_close_buffered(afd);
429       }
430 
431       cr = lives_painter_create_from_surface(mainw->laudio_drawable);
432       offset_right = NORMAL_CLAMP(offset_right, cfile->laudio_time * scalex);
433       xwidth = UTIL_CLAMP(width, allocwidth);
434       if (offset_end > posx + xwidth) offset_end = posx + xwidth;
435       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
436       lpos = -9999;
437       lives_painter_move_to(cr, posx, bar_height);
438       for (i = posx; i < offset_left && i < offset_end; i++) {
439         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
440         if (pos != lpos) {
441           lpos = pos;
442           y = bar_height * (1. - cfile->audio_waveform[0][pos] / 2.);
443         }
444 
445         lives_painter_line_to(cr, i, bar_height);
446         lives_painter_line_to(cr, i, y);
447         lives_painter_line_to(cr, i, bar_height);
448       }
449       lives_painter_close_path(cr);
450       lives_painter_stroke(cr);
451 
452       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_sel);
453       lpos = -9999;
454 
455       lives_painter_move_to(cr, i, bar_height);
456       for (; i < offset_right && i < offset_end; i++) {
457         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
458         if (pos != lpos) {
459           lpos = pos;
460           y = bar_height * (1. - cfile->audio_waveform[0][pos] / 2.);
461         }
462 
463         lives_painter_line_to(cr, i, bar_height);
464         lives_painter_line_to(cr, i, y);
465         lives_painter_line_to(cr, i, bar_height);
466       }
467       lives_painter_close_path(cr);
468       lives_painter_stroke(cr);
469 
470       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
471       lpos = -9999;
472       lives_painter_move_to(cr, offset_right, bar_height);
473       for (; i < offset_end; i++) {
474         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
475         if (pos != lpos) {
476           lpos = pos;
477           y = bar_height * (1. - cfile->audio_waveform[0][pos] / 2.);
478         }
479 
480         lives_painter_line_to(cr, i, bar_height);
481         lives_painter_line_to(cr, i, y);
482         lives_painter_line_to(cr, i, bar_height);
483       }
484       lives_painter_close_path(cr);
485       lives_painter_stroke(cr);
486       lives_painter_destroy(cr);
487     }
488   }
489 
490   if (cfile->achans > 1 && mainw->raudio_drawable && (which == 0 || which == 3)) {
491     allocwidth = lives_widget_get_allocation_width(mainw->raudio_draw);
492     scalex = (double)allocwidth / CURRENT_CLIP_TOTAL_TIME;
493     offset_left = ROUND_I((double)(cfile->start - 1.) / cfile->fps * scalex);
494     offset_right = ROUND_I((double)(cfile->end) / cfile->fps * scalex);
495     offset_end = ROUND_I(cfile->raudio_time * scalex);
496 
497     start = offset_end;
498     if (!cfile->audio_waveform[1]) {
499       // re-read the audio and force a redraw
500       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(mainw->raudio_draw), "drawn", LIVES_INT_TO_POINTER(0));
501       cfile->audio_waveform[1] = (float *)lives_calloc((int)offset_end, sizeof(float));
502       start = cfile->aw_sizes[1] = 0;
503     } else if (cfile->aw_sizes[1] != offset_end) {
504       start = 0;
505       cfile->audio_waveform[1] = (float *)lives_realloc(cfile->audio_waveform[1], (int)offset_end * sizeof(float));
506     }
507     cfile->aw_sizes[1] = offset_end;
508 
509     if (cfile->audio_waveform[1]) {
510       if (start != offset_end) {
511         cfile->aw_sizes[1] = offset_end;
512         filename = lives_get_audio_file_name(mainw->current_file);
513         afd = lives_open_buffered_rdonly(filename);
514         lives_free(filename);
515         for (i = start; i < offset_end; i++) {
516           if (afd == -1) {
517             THREADVAR(read_failed) = -2;
518             return;
519           }
520           atime = (double)i / scalex;
521           cfile->audio_waveform[1][i] = cfile->vol
522                                         * get_float_audio_val_at_time(mainw->current_file, afd, atime, 1, cfile->achans) * 2.;
523         }
524         lives_close_buffered(afd);
525         afd = -1;
526       }
527 
528       offset_right = NORMAL_CLAMP(offset_right, cfile->raudio_time * scalex);
529       xwidth = UTIL_CLAMP(width, allocwidth);
530 
531       cr = lives_painter_create_from_surface(mainw->raudio_drawable);
532       if (offset_end > posx + xwidth) offset_end = posx + xwidth;
533       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
534       lpos = -9999;
535       lives_painter_move_to(cr, posx, bar_height);
536       for (i = posx; i < offset_left && i < offset_end; i++) {
537         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
538         if (pos != lpos) {
539           lpos = pos;
540           y = bar_height * (1. - cfile->audio_waveform[1][pos] / 2.);
541         }
542 
543         lives_painter_line_to(cr, i, bar_height);
544         lives_painter_line_to(cr, i, y);
545         lives_painter_line_to(cr, i, bar_height);
546       }
547       lives_painter_close_path(cr);
548       lives_painter_stroke(cr);
549 
550       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_sel);
551       lpos = -9999;
552 
553       lives_painter_move_to(cr, i, bar_height);
554       for (; i < offset_right && i < offset_end; i++) {
555         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
556         if (pos != lpos) {
557           lpos = pos;
558           y = bar_height * (1. - cfile->audio_waveform[1][pos] / 2.);
559         }
560 
561         lives_painter_line_to(cr, i, bar_height);
562         lives_painter_line_to(cr, i, y);
563         lives_painter_line_to(cr, i, bar_height);
564       }
565       lives_painter_close_path(cr);
566       lives_painter_stroke(cr);
567 
568       lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->ce_unsel);
569       lpos = -9999;
570       lives_painter_move_to(cr, offset_right, bar_height);
571       for (; i < offset_end; i++) {
572         pos = ROUND_I((double)(i * cfile->fps / scalex) / cfile->fps * scalex);
573         if (pos != lpos) {
574           lpos = pos;
575           y = bar_height * (1. - cfile->audio_waveform[1][pos] / 2.);
576         }
577 
578         lives_painter_line_to(cr, i, bar_height);
579         lives_painter_line_to(cr, i, y);
580         lives_painter_line_to(cr, i, bar_height);
581       }
582       lives_painter_close_path(cr);
583       lives_painter_stroke(cr);
584       lives_painter_destroy(cr);
585     }
586   }
587 
588   if (which == 0) {
589     // playback cursors
590     if (CURRENT_CLIP_TOTAL_TIME > 0.) {
591       // set the range of the timeline
592       if (!cfile->opening_loc && which == 0) {
593         if (!lives_widget_is_visible(mainw->hruler)) {
594           lives_widget_show(mainw->hruler);
595         }
596       }
597 
598       if (!lives_widget_is_visible(mainw->video_draw)) {
599         lives_widget_show(mainw->hruler);
600         lives_widget_show(mainw->video_draw);
601         lives_widget_show(mainw->laudio_draw);
602         lives_widget_show(mainw->raudio_draw);
603       }
604 
605 #ifdef ENABLE_GIW
606       giw_timeline_set_max_size(GIW_TIMELINE(mainw->hruler), CURRENT_CLIP_TOTAL_TIME);
607 #endif
608       lives_ruler_set_upper(LIVES_RULER(mainw->hruler), CURRENT_CLIP_TOTAL_TIME);
609       lives_widget_queue_draw(mainw->hruler);
610     }
611     show_playbar_labels(mainw->current_file);
612   }
613   //lives_widget_queue_draw_if_visible(mainw->hruler);
614 
615 
616   mainw->current_file = current_file;
617   if (which == 0 || which == 1) lives_widget_queue_draw_if_visible(mainw->video_draw);
618   if (which == 0 || which == 2) lives_widget_queue_draw_if_visible(mainw->laudio_draw);
619   if (which == 0 || which == 3) lives_widget_queue_draw_if_visible(mainw->raudio_draw);
620 }
621 
622 
redraw_timer_bars(double oldx,double newx,int which)623 void redraw_timer_bars(double oldx, double newx, int which) {
624   // redraw region from cache
625   // oldx and newx are in seconds
626   double scalex;
627   int allocwidth;
628 
629   if (oldx == newx) return;
630   if (CURRENT_CLIP_TOTAL_TIME == 0.) return;
631 
632   allocwidth = lives_widget_get_allocation_width(mainw->video_draw);
633 
634   if (allocwidth == 0) return;
635 
636   scalex = allocwidth / CURRENT_CLIP_TOTAL_TIME;
637 
638   if (newx > oldx) {
639     update_timer_bars(ROUND_I(oldx * scalex - .5), 0, ROUND_I((newx - oldx) * scalex + .5), 0, which);
640   } else {
641     update_timer_bars(ROUND_I(newx * scalex - .5), 0, ROUND_I((oldx - newx) * scalex + .5), 0, which);
642   }
643 }
644 
645 
on_fsp_click(LiVESWidget * widget,LiVESXEventButton * event,livespointer user_data)646 static boolean on_fsp_click(LiVESWidget *widget, LiVESXEventButton *event, livespointer user_data) {
647   lives_button_clicked(LIVES_BUTTON(user_data));
648   return FALSE;
649 }
650 
651 
widget_add_preview(LiVESWidget * widget,LiVESBox * for_preview,LiVESBox * for_button,LiVESBox * for_deint,int preview_type)652 void widget_add_preview(LiVESWidget *widget, LiVESBox *for_preview, LiVESBox *for_button, LiVESBox *for_deint,
653                         int preview_type) {
654   LiVESWidget *preview_button = NULL;
655 
656   if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO || preview_type == LIVES_PREVIEW_TYPE_RANGE ||
657       preview_type == LIVES_PREVIEW_TYPE_IMAGE_ONLY) {
658     mainw->fs_playframe = lives_standard_frame_new(_("Preview"), 0.5, FALSE);
659     mainw->fs_playalign = lives_alignment_new(0.5, 0.5, 1., 1.);
660 
661     mainw->fs_playimg = lives_drawing_area_new();
662     lives_widget_set_no_show_all(mainw->fs_playimg, TRUE);
663     lives_widget_set_app_paintable(mainw->fs_playimg, TRUE);
664 
665     mainw->fs_playarea = lives_event_box_new();
666 
667     lives_widget_nullify_with(widget, (void **)&mainw->fs_playframe);
668     lives_widget_nullify_with(widget, (void **)&mainw->fs_playarea);
669     lives_widget_nullify_with(widget, (void **)&mainw->fs_playalign);
670     lives_widget_nullify_with(widget, (void **)&mainw->fs_playimg);
671 
672     lives_widget_set_events(mainw->fs_playframe, LIVES_BUTTON_PRESS_MASK);
673 
674     lives_widget_apply_theme(mainw->fs_playframe, LIVES_WIDGET_STATE_NORMAL);
675     lives_widget_apply_theme(mainw->fs_playalign, LIVES_WIDGET_STATE_NORMAL);
676     lives_widget_set_fg_color(mainw->fs_playalign, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
677 
678     lives_widget_apply_theme(mainw->fs_playarea, LIVES_WIDGET_STATE_NORMAL);
679 
680     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(mainw->fs_playarea), "pixbuf", NULL);
681 
682     lives_container_set_border_width(LIVES_CONTAINER(mainw->fs_playframe), 0);
683 
684     lives_box_pack_start(for_preview, mainw->fs_playframe, FALSE, TRUE, 0);
685 
686     if (preview_type != LIVES_PREVIEW_TYPE_RANGE) {
687       lives_widget_set_size_request(mainw->fs_playframe,
688                                     ((int)(DEF_FRAME_HSIZE_UNSCALED * (widget_opts.scale < 1.
689                                            ? widget_opts.scale : 1.)) >> 2) << 1,
690                                     ((int)(DEF_FRAME_VSIZE_UNSCALED * (widget_opts.scale < 1.
691                                            ? widget_opts.scale : 1.)) >> 2) << 1);
692     } else {
693       lives_widget_set_vexpand(mainw->fs_playframe, TRUE);
694     }
695     lives_container_add(LIVES_CONTAINER(mainw->fs_playframe), mainw->fs_playalign);
696     lives_container_add(LIVES_CONTAINER(mainw->fs_playalign), mainw->fs_playarea);
697     lives_container_add(LIVES_CONTAINER(mainw->fs_playarea), mainw->fs_playimg);
698   } else mainw->fs_playframe = mainw->fs_playalign = mainw->fs_playarea = mainw->fs_playimg = NULL; // AUDIO_ONLY
699 
700   if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO) {
701     preview_button =
702       lives_standard_button_new_with_label(_("Click here to _Preview the Selected Video, "
703                                            "Image or Audio File"),
704                                            DEF_BUTTON_WIDTH * 4, DEF_BUTTON_HEIGHT);
705   } else if (preview_type == LIVES_PREVIEW_TYPE_AUDIO_ONLY) {
706     preview_button = lives_standard_button_new_with_label(_("Click here to _Preview the Selected "
707                      "Audio File"), DEF_BUTTON_WIDTH * 4, DEF_BUTTON_HEIGHT);
708   } else if (preview_type == LIVES_PREVIEW_TYPE_RANGE) {
709     widget_opts.expand = LIVES_EXPAND_NONE;
710     preview_button = lives_standard_button_new_with_label(_("\nClick here to _Preview the Selection\n"),
711                      DEF_BUTTON_WIDTH * 4, DEF_BUTTON_HEIGHT);
712     lives_widget_set_hexpand(mainw->fs_playframe, TRUE);
713     lives_widget_set_vexpand(mainw->fs_playframe, TRUE);
714     lives_widget_set_halign(preview_button, LIVES_ALIGN_CENTER);
715     widget_opts.expand = LIVES_EXPAND_DEFAULT;
716   } else {
717     preview_button = lives_standard_button_new_with_label(_("Click here to _Preview the file"),
718                      DEF_BUTTON_WIDTH * 4, DEF_BUTTON_HEIGHT);
719   }
720 
721   if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO || preview_type == LIVES_PREVIEW_TYPE_RANGE ||
722       preview_type == LIVES_PREVIEW_TYPE_IMAGE_ONLY) {
723     lives_box_pack_start(for_button, preview_button, FALSE, FALSE, widget_opts.packing_width);
724     lives_signal_connect(LIVES_GUI_OBJECT(mainw->fs_playframe), LIVES_WIDGET_BUTTON_PRESS_EVENT,
725                          LIVES_GUI_CALLBACK(on_fsp_click), preview_button);
726   }
727 
728   if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO || preview_type == LIVES_PREVIEW_TYPE_RANGE) {
729     add_deinterlace_checkbox(for_deint);
730   }
731 
732   lives_signal_sync_connect(LIVES_GUI_OBJECT(preview_button), LIVES_WIDGET_CLICKED_SIGNAL,
733                             LIVES_GUI_CALLBACK(on_fs_preview_clicked), LIVES_INT_TO_POINTER(preview_type));
734 
735   if (LIVES_IS_FILE_CHOOSER(widget) && preview_type != LIVES_PREVIEW_TYPE_RANGE) {
736     lives_widget_set_sensitive(preview_button, FALSE);
737 
738     lives_signal_sync_connect(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_SELECTION_CHANGED_SIGNAL,
739                               LIVES_GUI_CALLBACK(pv_sel_changed), (livespointer)preview_button);
740   }
741 }
742 
743 
on_dth_cancel_clicked(LiVESButton * button,livespointer user_data)744 static void on_dth_cancel_clicked(LiVESButton *button, livespointer user_data) {
745   if (LIVES_POINTER_TO_INT(user_data) == 1) mainw->cancelled = CANCEL_KEEP;
746   else mainw->cancelled = CANCEL_USER;
747 }
748 
749 
750 static ticks_t last_t;
751 
create_threaded_dialog(char * text,boolean has_cancel,boolean * td_had_focus)752 xprocess *create_threaded_dialog(char *text, boolean has_cancel, boolean *td_had_focus) {
753   LiVESWidget *dialog_vbox;
754   LiVESWidget *vbox;
755   LiVESWidget *hbox;
756   xprocess *procw;
757   char tmp_label[256];
758 
759   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
760 
761   last_t = lives_get_current_ticks();
762 
763   procw = (xprocess *)(lives_calloc(sizeof(xprocess), 1));
764 
765   procw->processing = lives_standard_dialog_new(_("Processing..."), FALSE, -1, -1);
766 
767   lives_window_set_decorated(LIVES_WINDOW(procw->processing), FALSE);
768 
769   lives_window_add_accel_group(LIVES_WINDOW(procw->processing), accel_group);
770 
771   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(procw->processing));
772 
773   vbox = lives_vbox_new(FALSE, 0);
774   lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox, TRUE, TRUE, 0);
775 
776   lives_snprintf(tmp_label, 256, "%s...\n", text);
777   widget_opts.justify = LIVES_JUSTIFY_CENTER;
778   widget_opts.mnemonic_label = FALSE;
779   procw->label = lives_standard_label_new(tmp_label);
780   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
781   widget_opts.mnemonic_label = TRUE;
782   lives_box_pack_start(LIVES_BOX(vbox), procw->label, FALSE, TRUE, 0);
783 
784   procw->progressbar = lives_standard_progress_bar_new();
785 
786   lives_progress_bar_set_pulse_step(LIVES_PROGRESS_BAR(procw->progressbar), .01);
787   lives_box_pack_start(LIVES_BOX(vbox), procw->progressbar, FALSE, FALSE, 0);
788 
789   if (widget_opts.apply_theme && (palette->style & STYLE_1)) {
790     lives_widget_set_fg_color(procw->progressbar, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
791   }
792 
793   widget_opts.justify = LIVES_JUSTIFY_CENTER;
794   procw->label2 = lives_standard_label_new(_("\nPlease Wait"));
795   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
796   lives_box_pack_start(LIVES_BOX(vbox), procw->label2, FALSE, FALSE, 0);
797 
798   widget_opts.justify = LIVES_JUSTIFY_CENTER;
799 #ifdef PROGBAR_IS_ENTRY
800   procw->label3 = procw->progressbar;
801 #else
802   procw->label3 = lives_standard_label_new("");
803   lives_box_pack_start(LIVES_BOX(vbox), procw->label3, FALSE, FALSE, 0);
804 #endif
805   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
806   widget_opts.expand = LIVES_EXPAND_EXTRA;
807   hbox = lives_hbox_new(FALSE, widget_opts.filler_len * 8);
808   add_fill_to_box(LIVES_BOX(hbox));
809   add_fill_to_box(LIVES_BOX(hbox));
810   widget_opts.expand = LIVES_EXPAND_DEFAULT;
811   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
812 
813   if (has_cancel) {
814     if (CURRENT_CLIP_IS_VALID && mainw->cancel_type == CANCEL_SOFT) {
815       LiVESWidget *enoughbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), NULL, _("_Enough"),
816                                   LIVES_RESPONSE_CANCEL);
817       lives_widget_set_can_default(enoughbutton, TRUE);
818 
819       lives_signal_sync_connect(LIVES_GUI_OBJECT(enoughbutton), LIVES_WIDGET_CLICKED_SIGNAL,
820                                 LIVES_GUI_CALLBACK(on_dth_cancel_clicked), LIVES_INT_TO_POINTER(1));
821 
822       lives_widget_add_accelerator(enoughbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
823                                    LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
824       lives_button_uncenter(enoughbutton, DLG_BUTTON_WIDTH);
825     } else {
826       procw->cancel_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), LIVES_STOCK_CANCEL, NULL,
827                              LIVES_RESPONSE_CANCEL);
828       lives_widget_set_can_default(procw->cancel_button, TRUE);
829 
830       lives_widget_add_accelerator(procw->cancel_button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
831                                    LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
832 
833       lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->cancel_button), LIVES_WIDGET_CLICKED_SIGNAL,
834                                 LIVES_GUI_CALLBACK(on_dth_cancel_clicked), LIVES_INT_TO_POINTER(0));
835       lives_button_uncenter(procw->cancel_button, DLG_BUTTON_WIDTH);
836     }
837   }
838 
839   if (lives_has_toplevel_focus(LIVES_MAIN_WINDOW_WIDGET)) {
840     *td_had_focus = TRUE;
841   } else *td_had_focus = FALSE;
842 
843   lives_widget_show_all(procw->processing);
844 
845   lives_set_cursor_style(LIVES_CURSOR_BUSY, procw->processing);
846   lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
847 
848   procw->is_ready = TRUE;
849   return procw;
850 }
851 
852 
create_processing(const char * text)853 xprocess *create_processing(const char *text) {
854   LiVESWidget *dialog_vbox;
855   LiVESWidget *hbox;
856   LiVESWidget *vbox2;
857   LiVESWidget *vbox3;
858 
859   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
860 
861   xprocess *procw = (xprocess *)(lives_malloc(sizeof(xprocess)));
862 
863   char tmp_label[256];
864   boolean markup = widget_opts.use_markup;
865 
866   widget_opts.use_markup = FALSE;
867 
868   procw->frac_done = -1.;
869 
870   procw->processing = lives_standard_dialog_new(_("Processing..."), FALSE, -1, -1);
871 
872   lives_window_set_decorated(LIVES_WINDOW(procw->processing), FALSE);
873 
874   if (prefs->gui_monitor != 0) {
875     lives_window_set_monitor(LIVES_WINDOW(procw->processing), widget_opts.monitor);
876   }
877 
878   lives_window_add_accel_group(LIVES_WINDOW(procw->processing), accel_group);
879 
880   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(procw->processing));
881 
882   vbox2 = lives_vbox_new(FALSE, 0);
883   lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox2, TRUE, TRUE, 0);
884 
885   vbox3 = lives_vbox_new(FALSE, 0);
886   lives_box_pack_start(LIVES_BOX(vbox2), vbox3, TRUE, TRUE, 0);
887 
888   widget_opts.use_markup = markup;
889   lives_snprintf(tmp_label, 256, "%s...\n", text);
890   widget_opts.use_markup = FALSE;
891   widget_opts.justify = LIVES_JUSTIFY_CENTER;
892   widget_opts.mnemonic_label = FALSE;
893   procw->label = lives_standard_label_new(tmp_label);
894   widget_opts.mnemonic_label = TRUE;
895   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
896 
897   lives_box_pack_start(LIVES_BOX(vbox3), procw->label, TRUE, TRUE, 0);
898 
899   procw->progressbar = lives_standard_progress_bar_new();
900 
901   lives_box_pack_start(LIVES_BOX(vbox3), procw->progressbar, FALSE, FALSE, 0);
902   if (palette->style & STYLE_1) {
903     lives_widget_set_fg_color(procw->progressbar, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
904   }
905 
906   widget_opts.justify = LIVES_JUSTIFY_CENTER;
907   if (mainw->internal_messaging && mainw->rte != 0 && !mainw->transrend_proc) {
908     procw->label2 = lives_standard_label_new(_("\n\nPlease Wait\n\nRemember to switch off effects (ctrl-0) afterwards !"));
909   } else procw->label2 = lives_standard_label_new(_("\nPlease Wait"));
910   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
911 
912   lives_box_pack_start(LIVES_BOX(vbox3), procw->label2, FALSE, FALSE, 0);
913 
914   widget_opts.justify = LIVES_JUSTIFY_CENTER;
915 #ifdef PROGBAR_IS_ENTRY
916   procw->label3 = procw->progressbar;
917 #else
918   procw->label3 = lives_standard_label_new("");
919   lives_box_pack_start(LIVES_BOX(vbox3), procw->label3, FALSE, FALSE, 0);
920 #endif
921   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
922 
923   widget_opts.expand = LIVES_EXPAND_EXTRA;
924   hbox = lives_hbox_new(FALSE, widget_opts.filler_len * 8);
925   add_fill_to_box(LIVES_BOX(hbox));
926   add_fill_to_box(LIVES_BOX(hbox));
927   widget_opts.expand = LIVES_EXPAND_DEFAULT;
928 
929   lives_box_pack_start(LIVES_BOX(vbox3), hbox, FALSE, FALSE, 0);
930 
931   if (mainw->iochan) {
932     // add "show details" arrow
933     int woat = widget_opts.apply_theme;
934     widget_opts.apply_theme = 0;
935     widget_opts.expand = LIVES_EXPAND_EXTRA;
936     procw->scrolledwindow = lives_standard_scrolled_window_new(ENC_DETAILS_WIN_H, ENC_DETAILS_WIN_V,
937                             LIVES_WIDGET(mainw->optextview));
938     widget_opts.expand = LIVES_EXPAND_DEFAULT;
939     widget_opts.apply_theme = woat;
940     lives_standard_expander_new(_("Show Details"), LIVES_BOX(vbox3), procw->scrolledwindow);
941   }
942 
943   procw->stop_button = procw->preview_button = procw->pause_button = NULL;
944 
945   if (CURRENT_CLIP_IS_VALID) {
946     if (cfile->opening_loc
947 #ifdef ENABLE_JACK
948         || mainw->jackd_read
949 #endif
950 #ifdef HAVE_PULSE_AUDIO
951         || mainw->pulsed_read
952 #endif
953        ) {
954       // the "enough" button for opening
955       procw->stop_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), NULL, _("_Enough"),
956                            LIVES_RESPONSE_ACCEPT); // used only for open location and for audio recording
957       lives_widget_set_can_default(procw->stop_button, TRUE);
958     }
959 
960     if (cfile->nokeep) procw->pause_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing),
961           NULL, _("Paus_e"), LIVES_RESPONSE_ACCEPT);
962     else procw->pause_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), NULL, _("Pause/_Enough"),
963                                  LIVES_RESPONSE_ACCEPT);
964     lives_widget_set_can_default(procw->pause_button, TRUE);
965 
966     procw->preview_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), NULL, _("_Preview"),
967                             LIVES_RESPONSE_SHOW_DETAILS);
968     lives_widget_set_can_default(procw->preview_button, TRUE);
969   }
970 
971   procw->cancel_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(procw->processing), LIVES_STOCK_CANCEL, NULL,
972                          LIVES_RESPONSE_CANCEL);
973 
974   lives_widget_set_can_default(procw->cancel_button, TRUE);
975   lives_button_grab_default_special(procw->cancel_button);
976 
977   lives_widget_add_accelerator(procw->cancel_button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
978                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
979 
980   if (procw->stop_button)
981     lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->stop_button), LIVES_WIDGET_CLICKED_SIGNAL,
982                               LIVES_GUI_CALLBACK(on_stop_clicked), NULL);
983 
984   lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->pause_button), LIVES_WIDGET_CLICKED_SIGNAL,
985                             LIVES_GUI_CALLBACK(on_effects_paused), NULL);
986 
987   if (mainw->multitrack && mainw->multitrack->is_rendering) {
988     lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->preview_button), LIVES_WIDGET_CLICKED_SIGNAL,
989                               LIVES_GUI_CALLBACK(multitrack_preview_clicked), mainw->multitrack);
990   } else {
991     lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->preview_button), LIVES_WIDGET_CLICKED_SIGNAL,
992                               LIVES_GUI_CALLBACK(on_preview_clicked), NULL);
993   }
994 
995   lives_signal_sync_connect(LIVES_GUI_OBJECT(procw->cancel_button), LIVES_WIDGET_CLICKED_SIGNAL,
996                             LIVES_GUI_CALLBACK(on_cancel_keep_button_clicked), NULL);
997 
998   if (mainw->show_procd) lives_widget_show_all(procw->processing);
999   if (procw->preview_button) lives_widget_hide(procw->preview_button);
1000   if (procw->pause_button) lives_widget_hide(procw->pause_button);
1001 
1002   if (procw->stop_button) lives_widget_hide(procw->stop_button);
1003 
1004   return procw;
1005 }
1006 
1007 
vid_text_view_new(void)1008 static LiVESWidget *vid_text_view_new(void) {
1009   LiVESWidget *textview;
1010   widget_opts.justify = LIVES_JUSTIFY_CENTER;
1011   textview = lives_standard_text_view_new(NULL, NULL);
1012   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1013   lives_widget_set_size_request(textview, TB_WIDTH, TB_HEIGHT_VID);
1014   if (palette->style & STYLE_3) {
1015     lives_widget_set_bg_color(textview, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1016   }
1017   if (mainw->multitrack) {
1018     lives_text_view_set_top_margin(LIVES_TEXT_VIEW(textview), 2);
1019     lives_text_view_set_bottom_margin(LIVES_TEXT_VIEW(textview), 20);
1020     lives_widget_set_valign(textview, LIVES_ALIGN_FILL);
1021   } else {
1022     lives_text_view_set_bottom_margin(LIVES_TEXT_VIEW(textview), TB_HEIGHT_VID >> 2);
1023     lives_text_view_set_top_margin(LIVES_TEXT_VIEW(textview), TB_HEIGHT_VID >> 2);
1024   }
1025   return textview;
1026 }
1027 
1028 
aud_text_view_new(void)1029 static LiVESWidget *aud_text_view_new(void) {
1030   LiVESWidget *textview;
1031   widget_opts.justify = LIVES_JUSTIFY_CENTER;
1032   textview = lives_standard_text_view_new(NULL, NULL);
1033   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1034   lives_widget_set_size_request(textview, TB_WIDTH, TB_HEIGHT_AUD);
1035   if (palette->style & STYLE_3) {
1036     lives_widget_set_bg_color(textview, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1037   }
1038   if (mainw->multitrack) {
1039     lives_text_view_set_bottom_margin(LIVES_TEXT_VIEW(textview), 20);
1040   } else {
1041     lives_text_view_set_bottom_margin(LIVES_TEXT_VIEW(textview), TB_HEIGHT_AUD >> 2);
1042     lives_text_view_set_top_margin(LIVES_TEXT_VIEW(textview), TB_HEIGHT_AUD >> 2);
1043   }
1044   return textview;
1045 }
1046 
1047 
create_clip_info_window(int audio_channels,boolean is_mt)1048 lives_clipinfo_t *create_clip_info_window(int audio_channels, boolean is_mt) {
1049   LiVESWidget *dialog_vbox;
1050   LiVESWidget *table;
1051   LiVESWidget *label;
1052   LiVESWidget *vidframe;
1053   LiVESWidget *laudframe;
1054   LiVESWidget *raudframe;
1055   LiVESWidget *okbutton;
1056   LiVESWidget *vbox;
1057   LiVESWidget *hbox;
1058   LiVESWidget *layout;
1059 
1060   LiVESAccelGroup *accel_group;
1061 
1062   lives_clipinfo_t *filew = (lives_clipinfo_t *)(lives_malloc(sizeof(lives_clipinfo_t)));
1063 
1064   char *title;
1065   char *tmp;
1066 
1067   int offset = 0;
1068 
1069   if (!is_mt)
1070     title = get_menu_name(cfile, TRUE);
1071   else {
1072     offset = 2;
1073     title = (_("Multitrack Details"));
1074   }
1075 
1076   filew->dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
1077   lives_free(title);
1078 
1079   lives_signal_handlers_disconnect_by_func(filew->dialog, LIVES_GUI_CALLBACK(return_true), NULL);
1080 
1081   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1082   lives_window_add_accel_group(LIVES_WINDOW(filew->dialog), accel_group);
1083 
1084   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(filew->dialog));
1085   lives_container_set_border_width(LIVES_CONTAINER(dialog_vbox), 2);
1086 
1087   if (cfile->frames > 0 || is_mt) {
1088     vidframe = lives_standard_frame_new(_("Video"), 0., FALSE);
1089 
1090     lives_box_pack_start(LIVES_BOX(dialog_vbox), vidframe, TRUE, TRUE, 0);
1091 
1092     vbox = lives_vbox_new(FALSE, 0);
1093     lives_container_add(LIVES_CONTAINER(vidframe), vbox);
1094     lives_container_set_border_width(LIVES_CONTAINER(vbox), widget_opts.border_width);
1095 
1096     layout = lives_layout_new(LIVES_BOX(vbox));
1097 
1098     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("Format"), TRUE);
1099     if (palette->style & STYLE_3) {
1100       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1101     }
1102 
1103     filew->textview_type = vid_text_view_new();
1104     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1105     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_type);
1106     lives_widget_set_valign(filew->textview_type, LIVES_ALIGN_FILL);
1107 
1108     widget_opts.expand |= LIVES_EXPAND_EXTRA_WIDTH;
1109     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1110     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1111 
1112     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("FPS"), TRUE);
1113     if (palette->style & STYLE_3) {
1114       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1115     }
1116 
1117     filew->textview_fps = vid_text_view_new();
1118     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1119     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_fps);
1120 
1121     lives_layout_add_row(LIVES_LAYOUT(layout));
1122 
1123     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("Frame Size"), TRUE);
1124     if (palette->style & STYLE_3) {
1125       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1126     }
1127 
1128     filew->textview_size = vid_text_view_new();
1129     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1130     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_size);
1131 
1132     widget_opts.expand |= LIVES_EXPAND_EXTRA_WIDTH;
1133     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1134     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1135 
1136     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("Frames"), TRUE);
1137     if (palette->style & STYLE_3) {
1138       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1139     }
1140 
1141     filew->textview_frames = vid_text_view_new();
1142     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1143     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_frames);
1144     lives_widget_set_valign(filew->textview_frames, LIVES_ALIGN_FILL);
1145 
1146     lives_layout_add_row(LIVES_LAYOUT(layout));
1147 
1148     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("File Size"), TRUE);
1149     if (palette->style & STYLE_3) {
1150       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1151     }
1152 
1153     filew->textview_fsize = vid_text_view_new();
1154     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1155     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_fsize);
1156 
1157     widget_opts.expand |= LIVES_EXPAND_EXTRA_WIDTH;
1158     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1159     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1160 
1161     label = lives_layout_add_label(LIVES_LAYOUT(layout), _("Total Time"), TRUE);
1162     if (palette->style & STYLE_3) {
1163       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1164     }
1165 
1166     filew->textview_vtime = vid_text_view_new();
1167     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1168     lives_layout_pack(LIVES_HBOX(hbox), filew->textview_vtime);
1169     if (mainw->multitrack) lives_text_view_set_top_margin(LIVES_TEXT_VIEW(filew->textview_vtime), 10);
1170   }
1171 
1172   if (audio_channels > 0) {
1173     if (audio_channels > 1) tmp = get_achannel_name(2, 0);
1174     else tmp = (_("Audio"));
1175 
1176     laudframe = lives_standard_frame_new(tmp, 0., FALSE);
1177     lives_free(tmp);
1178 
1179     lives_box_pack_start(LIVES_BOX(dialog_vbox), laudframe, TRUE, TRUE, 0);
1180 
1181     table = lives_table_new(1, 4, TRUE);
1182 
1183     lives_table_set_col_spacings(LIVES_TABLE(table), widget_opts.packing_width * 4);
1184     lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height);
1185     lives_container_set_border_width(LIVES_CONTAINER(table), widget_opts.border_width);
1186 
1187     lives_container_add(LIVES_CONTAINER(laudframe), table);
1188 
1189     label = lives_standard_label_new(_("Rate/size"));
1190     if (palette->style & STYLE_3) {
1191       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1192     }
1193     lives_label_set_hpadding(LIVES_LABEL(label), 4);
1194     lives_table_attach(LIVES_TABLE(table), label, 0 + offset, 1 + offset, 0, 1,
1195                        (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1196 
1197     filew->textview_lrate = aud_text_view_new();
1198     lives_table_attach(LIVES_TABLE(table), filew->textview_lrate, 1 + offset, 2 + offset, 0, 1,
1199                        (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1200     lives_widget_set_valign(filew->textview_lrate, LIVES_ALIGN_FILL);
1201 
1202     if (!is_mt) {
1203       label = lives_standard_label_new(_("Total time"));
1204       if (palette->style & STYLE_3) {
1205         lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1206       }
1207       lives_table_attach(LIVES_TABLE(table), label, 2, 3, 0, 1,
1208                          (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1209 
1210       filew->textview_ltime = aud_text_view_new();
1211       lives_table_attach(LIVES_TABLE(table), filew->textview_ltime, 3, 4, 0, 1,
1212                          (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1213     }
1214   }
1215 
1216   if (audio_channels > 1) {
1217     tmp = get_achannel_name(2, 1);
1218     raudframe = lives_standard_frame_new(tmp, 0., FALSE);
1219     lives_free(tmp);
1220 
1221     lives_box_pack_start(LIVES_BOX(dialog_vbox), raudframe, TRUE, TRUE, 0);
1222 
1223     table = lives_table_new(1, 4, TRUE);
1224 
1225     lives_table_set_col_spacings(LIVES_TABLE(table), widget_opts.packing_width * 4);
1226     lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height);
1227     lives_container_set_border_width(LIVES_CONTAINER(table), widget_opts.border_width);
1228 
1229     lives_container_add(LIVES_CONTAINER(raudframe), table);
1230 
1231 
1232     label = lives_standard_label_new(_("Rate/size"));
1233     if (palette->style & STYLE_3) {
1234       lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1235     }
1236     lives_label_set_hpadding(LIVES_LABEL(label), 4);
1237     lives_table_attach(LIVES_TABLE(table), label, 0 + offset, 1 + offset, 0, 1,
1238                        (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1239 
1240     filew->textview_rrate = aud_text_view_new();
1241     lives_table_attach(LIVES_TABLE(table), filew->textview_rrate, 1 + offset, 2 + offset, 0, 1,
1242                        (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1243     lives_widget_set_valign(filew->textview_rrate, LIVES_ALIGN_FILL);
1244 
1245     if (!is_mt) {
1246       label = lives_standard_label_new(_("Total time"));
1247       if (palette->style & STYLE_3) {
1248         lives_widget_set_bg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
1249       }
1250       lives_label_set_hpadding(LIVES_LABEL(label), 4);
1251       lives_table_attach(LIVES_TABLE(table), label, 2, 3, 0, 1,
1252                          (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1253 
1254       filew->textview_rtime = aud_text_view_new();
1255       lives_table_attach(LIVES_TABLE(table), filew->textview_rtime, 3, 4, 0, 1,
1256                          (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
1257     }
1258   }
1259 
1260   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(filew->dialog), LIVES_STOCK_CLOSE, _("_Close Window"),
1261              LIVES_RESPONSE_OK);
1262   lives_button_grab_default_special(okbutton);
1263 
1264   lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
1265                             LIVES_GUI_CALLBACK(lives_general_button_clicked), filew);
1266 
1267   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1268   lives_window_add_accel_group(LIVES_WINDOW(filew->dialog), accel_group);
1269 
1270   lives_widget_add_accelerator(okbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
1271                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
1272 
1273   lives_widget_show_all(filew->dialog);
1274 
1275   return filew;
1276 }
1277 
1278 
on_resizecb_toggled(LiVESToggleButton * t,livespointer user_data)1279 static void on_resizecb_toggled(LiVESToggleButton *t, livespointer user_data) {
1280   LiVESWidget *cb = (LiVESWidget *)user_data;
1281 
1282   if (!lives_toggle_button_get_active(t)) {
1283     lives_widget_set_sensitive(cb, FALSE);
1284     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(cb), FALSE);
1285   } else {
1286     lives_widget_set_sensitive(cb, TRUE);
1287     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(cb), prefs->enc_letterbox);
1288   }
1289 }
1290 
1291 
create_encoder_prep_dialog(const char * text1,const char * text2,boolean opt_resize)1292 LiVESWidget *create_encoder_prep_dialog(const char *text1, const char *text2, boolean opt_resize) {
1293   LiVESWidget *dialog;
1294   LiVESWidget *dialog_vbox;
1295   LiVESWidget *okbutton;
1296   LiVESWidget *checkbutton = NULL;
1297   LiVESWidget *checkbutton2;
1298   LiVESWidget *label;
1299   LiVESWidget *hbox;
1300 
1301   char *labeltext, *tmp, *tmp2;
1302 
1303   dialog = create_question_dialog(_("Encoding Options"), text1);
1304   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
1305 
1306   if (opt_resize) {
1307     if (text2) labeltext = (_("<------------- (Check the box to re_size as suggested)"));
1308     else labeltext = (_("<------------- (Check the box to use the _size recommendation)"));
1309 
1310     hbox = lives_hbox_new(FALSE, 0);
1311     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_width);
1312 
1313     checkbutton = lives_standard_check_button_new(labeltext, FALSE, LIVES_BOX(hbox), NULL);
1314 
1315     lives_free(labeltext);
1316 
1317     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
1318                                     LIVES_GUI_CALLBACK(on_boolean_toggled),
1319                                     &mainw->fx1_bool);
1320   } else if (!text2) mainw->fx1_bool = TRUE;
1321 
1322   if (text2 && (mainw->fx1_bool || opt_resize)) {
1323     hbox = lives_hbox_new(FALSE, 0);
1324     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1325 
1326     checkbutton2 = lives_standard_check_button_new
1327                    ((tmp = (_("Use _letterboxing to maintain aspect ratio (optional)"))), FALSE, LIVES_BOX(hbox),
1328                     (tmp2 = (H_("Draw black rectangles either above or to the sides of the image, "
1329                                 "to prevent it from stretching."))));
1330 
1331     lives_free(tmp); lives_free(tmp2);
1332 
1333     if (opt_resize) {
1334       lives_widget_set_sensitive(checkbutton2, FALSE);
1335     } else lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(checkbutton2), prefs->enc_letterbox);
1336 
1337     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton2), LIVES_WIDGET_TOGGLED_SIGNAL,
1338                                     LIVES_GUI_CALLBACK(on_boolean_toggled), &prefs->enc_letterbox);
1339 
1340     if (opt_resize)
1341       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
1342                                       LIVES_GUI_CALLBACK(on_resizecb_toggled), checkbutton2);
1343   }
1344 
1345   if (text2) {
1346     label = lives_standard_label_new(text2);
1347     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, TRUE, TRUE, 0);
1348     lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
1349                                        LIVES_RESPONSE_CANCEL);
1350     okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL,
1351                LIVES_RESPONSE_OK);
1352   } else {
1353     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1354     lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), NULL, _("Keep _my settings"),
1355                                        LIVES_RESPONSE_CANCEL);
1356     okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), NULL, _("Use _recommended settings"),
1357                LIVES_RESPONSE_OK);
1358     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1359   }
1360 
1361   lives_button_grab_default_special(okbutton);
1362 
1363   lives_widget_show_all(dialog);
1364   return dialog;
1365 }
1366 
1367 
scrolled_textview(const char * text,LiVESTextBuffer * textbuffer,int window_width,LiVESWidget ** ptextview)1368 LiVESWidget *scrolled_textview(const char *text, LiVESTextBuffer *textbuffer, int window_width,
1369                                LiVESWidget **ptextview) {
1370   LiVESWidget *scrolledwindow = NULL;
1371   LiVESWidget *textview = lives_standard_text_view_new(text, textbuffer);
1372   if (textview) {
1373     int woex = widget_opts.expand;
1374     int height = RFX_WINSIZE_V;
1375     if (!LIVES_SHOULD_EXPAND_HEIGHT) height >>= 1;
1376     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1377     scrolledwindow = lives_standard_scrolled_window_new(window_width, height, textview);
1378     widget_opts.expand = woex;
1379     lives_container_set_border_width(LIVES_CONTAINER(scrolledwindow), widget_opts.border_width);
1380     if (palette->style & STYLE_1) {
1381       lives_widget_set_bg_color(lives_bin_get_child(LIVES_BIN(scrolledwindow)),
1382                                 LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
1383     }
1384   }
1385   if (ptextview) *ptextview = textview;
1386   return scrolledwindow;
1387 }
1388 
1389 
create_text_window(const char * title,const char * text,LiVESTextBuffer * textbuffer,boolean add_buttons)1390 text_window *create_text_window(const char *title, const char *text, LiVESTextBuffer *textbuffer,
1391                                 boolean add_buttons) {
1392   // general text window
1393   LiVESWidget *dialog_vbox;
1394   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1395 
1396   int woat;
1397   int window_width = RFX_WINSIZE_H;
1398 
1399   textwindow = (text_window *)lives_malloc(sizeof(text_window));
1400 
1401   if (LIVES_SHOULD_EXPAND_EXTRA_WIDTH) window_width
1402       = RFX_WINSIZE_H * 1.5 * widget_opts.scale;
1403 
1404   textwindow->dialog = lives_standard_dialog_new(title, FALSE, window_width,
1405                        LIVES_SHOULD_EXPAND_HEIGHT ? DEF_DIALOG_HEIGHT
1406                        : DEF_DIALOG_HEIGHT >> 1);
1407   lives_window_add_accel_group(LIVES_WINDOW(textwindow->dialog), accel_group);
1408 
1409   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(textwindow->dialog));
1410   textwindow->vbox = lives_vbox_new(FALSE, 0);
1411   lives_box_pack_start(LIVES_BOX(dialog_vbox), textwindow->vbox, TRUE, TRUE, 0);
1412 
1413   textwindow->textview = textwindow->table = NULL;
1414 
1415   woat = widget_opts.apply_theme;
1416   widget_opts.apply_theme = 0;
1417   if (textbuffer || text)
1418     textwindow->scrolledwindow = scrolled_textview(text, textbuffer, window_width, &textwindow->textview);
1419   else {
1420     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH;
1421     textwindow->table = lives_standard_table_new(1, 1, FALSE);
1422     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1423     textwindow->scrolledwindow = lives_standard_scrolled_window_new(window_width, RFX_WINSIZE_V, textwindow->table);
1424   }
1425   widget_opts.apply_theme = woat;
1426 
1427   lives_box_pack_start(LIVES_BOX(textwindow->vbox), textwindow->scrolledwindow, TRUE, TRUE, 0);
1428 
1429   if (add_buttons && (text || mainw->iochan || textwindow->table)) {
1430     if (!textwindow->table) {
1431       LiVESWidget *savebutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog),
1432                                 LIVES_STOCK_SAVE, _("_Save to file"), LIVES_RESPONSE_YES);
1433       lives_signal_sync_connect(LIVES_GUI_OBJECT(savebutton), LIVES_WIDGET_CLICKED_SIGNAL,
1434                                 LIVES_GUI_CALLBACK(on_save_textview_clicked), textwindow->textview);
1435     }
1436 
1437     textwindow->button = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog),
1438                          LIVES_STOCK_CLOSE, _("_Close Window"), LIVES_RESPONSE_CANCEL);
1439 
1440     lives_button_grab_default_special(textwindow->button);
1441 
1442     lives_signal_sync_connect(LIVES_GUI_OBJECT(textwindow->button), LIVES_WIDGET_CLICKED_SIGNAL,
1443                               LIVES_GUI_CALLBACK(lives_general_button_clicked), textwindow);
1444 
1445     lives_widget_add_accelerator(textwindow->button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
1446                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
1447     lives_widget_add_accelerator(textwindow->button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
1448                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
1449   }
1450 
1451   if (prefs->show_gui)
1452     lives_widget_show_all(textwindow->dialog);
1453 
1454   return textwindow;
1455 }
1456 
1457 
create_insert_dialog(void)1458 _insertw *create_insert_dialog(void) {
1459   LiVESWidget *dialog_vbox;
1460   LiVESWidget *hbox1;
1461   LiVESWidget *hbox;
1462   LiVESWidget *table;
1463   LiVESWidget *radiobutton;
1464   LiVESWidget *vseparator;
1465   LiVESWidget *cancelbutton;
1466   LiVESWidget *okbutton;
1467   LiVESWidget *label;
1468 
1469   LiVESSList *radiobutton1_group = NULL;
1470   LiVESSList *radiobutton2_group = NULL;
1471 
1472   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1473 
1474   char *tmp, *tmp2;
1475 
1476   _insertw *insertw = (_insertw *)(lives_malloc(sizeof(_insertw)));
1477 
1478   insertw->insert_dialog = lives_standard_dialog_new(_("Insert"), FALSE, -1, -1);
1479   lives_signal_handlers_disconnect_by_func(insertw->insert_dialog, LIVES_GUI_CALLBACK(return_true),
1480       NULL);
1481 
1482   lives_window_add_accel_group(LIVES_WINDOW(insertw->insert_dialog), accel_group);
1483 
1484   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(insertw->insert_dialog));
1485 
1486   hbox1 = lives_hbox_new(FALSE, 0);
1487 
1488   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox1, TRUE, TRUE, widget_opts.packing_height);
1489 
1490   hbox = lives_hbox_new(FALSE, 0);
1491   lives_box_pack_start(LIVES_BOX(hbox1), hbox, FALSE, FALSE, widget_opts.packing_width);
1492 
1493   insertw->spinbutton_times = lives_standard_spin_button_new(_("_Number of times to insert"),
1494                               1., 1., 10000., 1., 10., 0., LIVES_BOX(hbox), NULL);
1495 
1496   lives_widget_grab_focus(insertw->spinbutton_times);
1497 
1498   add_fill_to_box(LIVES_BOX(hbox1));
1499 
1500   hbox = lives_hbox_new(FALSE, 0);
1501 
1502   lives_box_pack_start(LIVES_BOX(hbox1), hbox, FALSE, FALSE, widget_opts.packing_width);
1503 
1504   if (cfile->frames == 0)
1505     insertw->fit_checkbutton = lives_standard_check_button_new(_("_Insert to fit audio"), mainw->fx1_bool, LIVES_BOX(hbox), NULL);
1506   else
1507     insertw->fit_checkbutton = lives_standard_check_button_new(_("_Insert from selection end to audio end"),
1508                                mainw->fx1_bool, LIVES_BOX(hbox), NULL);
1509   label = widget_opts.last_label;
1510   add_hsep_to_box(LIVES_BOX(dialog_vbox));
1511 
1512   table = lives_table_new(2, 3, FALSE);
1513   lives_box_pack_start(LIVES_BOX(dialog_vbox), table, TRUE, TRUE, widget_opts.packing_height);
1514   lives_table_set_col_spacings(LIVES_TABLE(table), widget_opts.packing_width * 4);
1515   lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height * 2);
1516 
1517   hbox = lives_hbox_new(FALSE, 0);
1518 
1519   radiobutton = lives_standard_radio_button_new((tmp = (_("Insert _before selection"))),
1520                 &radiobutton1_group, LIVES_BOX(hbox),
1521                 (tmp2 = (_("Insert clipboard before selected frames"))));
1522 
1523   lives_free(tmp);
1524   lives_free(tmp2);
1525 
1526   lives_table_attach(LIVES_TABLE(table), hbox, 0, 1, 0, 1,
1527                      (LiVESAttachOptions)(LIVES_FILL),
1528                      (LiVESAttachOptions)(0), 0, 0);
1529 
1530   if (cfile->frames == 0) lives_widget_set_sensitive(radiobutton, FALSE);
1531 
1532   toggle_sets_sensitive_cond(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), radiobutton, &cfile->frames, NULL, TRUE);
1533 
1534   hbox = lives_hbox_new(FALSE, 0);
1535 
1536   radiobutton = lives_standard_radio_button_new((tmp = (_("Insert _after selection"))),
1537                 &radiobutton1_group, LIVES_BOX(hbox),
1538                 (tmp2 = (_("Insert clipboard after selected frames"))));
1539 
1540   lives_table_attach(LIVES_TABLE(table), hbox, 0, 1, 1, 2,
1541                      (LiVESAttachOptions)(LIVES_FILL),
1542                      (LiVESAttachOptions)(0), 0, 0);
1543 
1544   toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(radiobutton), insertw->fit_checkbutton, FALSE);
1545   toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), radiobutton, TRUE);
1546   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton), mainw->insert_after);
1547 
1548   hbox = lives_hbox_new(FALSE, 0);
1549 
1550   if (clipboard->achans == 0)
1551     insertw->with_sound = lives_standard_radio_button_new(_("Insert _with silence"),
1552                           &radiobutton2_group, LIVES_BOX(hbox), NULL);
1553   else
1554     insertw->with_sound = lives_standard_radio_button_new(_("Insert _with sound"),
1555                           &radiobutton2_group, LIVES_BOX(hbox), NULL);
1556 
1557   lives_table_attach(LIVES_TABLE(table), hbox, 2, 3, 0, 1,
1558                      (LiVESAttachOptions)(LIVES_FILL),
1559                      (LiVESAttachOptions)(0), 0, 0);
1560 
1561   hbox = lives_hbox_new(FALSE, 0);
1562 
1563   insertw->without_sound = lives_standard_radio_button_new(_("Insert with_out sound"),
1564                            &radiobutton2_group, LIVES_BOX(hbox), NULL);
1565 
1566   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(insertw->with_sound),
1567                                  (cfile->achans > 0 || clipboard->achans > 0) && mainw->ccpd_with_sound);
1568 
1569   lives_table_attach(LIVES_TABLE(table), hbox, 2, 3, 1, 2,
1570                      (LiVESAttachOptions)(LIVES_FILL),
1571                      (LiVESAttachOptions)(0), 0, 0);
1572 
1573   vseparator = lives_vseparator_new();
1574   lives_table_attach(LIVES_TABLE(table), vseparator, 1, 2, 0, 1,
1575                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
1576                      (LiVESAttachOptions)(LIVES_FILL), 0, 0);
1577 
1578   vseparator = lives_vseparator_new();
1579   lives_table_attach(LIVES_TABLE(table), vseparator, 1, 2, 1, 2,
1580                      (LiVESAttachOptions)(LIVES_FILL),
1581                      (LiVESAttachOptions)(LIVES_FILL), 0, 0);
1582 
1583   add_fill_to_box(LIVES_BOX(dialog_vbox));
1584 
1585   if (cfile->achans == 0 || (double)cfile->end / cfile->fps >= cfile->laudio_time - 0.0001) {
1586     lives_widget_set_no_show_all(insertw->fit_checkbutton, TRUE);
1587     lives_widget_set_no_show_all(label, TRUE);
1588   } else {
1589     toggle_toggles_var(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), &mainw->fx1_bool, FALSE);
1590     toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), insertw->spinbutton_times, TRUE);
1591     toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), insertw->with_sound, TRUE);
1592     toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(insertw->fit_checkbutton), insertw->without_sound, TRUE);
1593   }
1594 
1595   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(insertw->insert_dialog), LIVES_STOCK_CANCEL, NULL,
1596                  LIVES_RESPONSE_CANCEL);
1597   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(insertw->insert_dialog), LIVES_STOCK_OK, NULL,
1598              LIVES_RESPONSE_OK);
1599 
1600   lives_button_grab_default_special(okbutton);
1601 
1602   lives_signal_sync_connect(LIVES_GUI_OBJECT(insertw->with_sound), LIVES_WIDGET_TOGGLED_SIGNAL,
1603                             LIVES_GUI_CALLBACK(on_insertwsound_toggled),  NULL);
1604   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
1605                             LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->insert_after);
1606   lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
1607                             LIVES_GUI_CALLBACK(lives_general_button_clicked), insertw);
1608   lives_signal_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
1609                        LIVES_GUI_CALLBACK(on_insert_activate), NULL);
1610   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(insertw->spinbutton_times), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
1611                                   LIVES_GUI_CALLBACK(on_spin_value_changed), LIVES_INT_TO_POINTER(1));
1612 
1613   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
1614                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
1615 
1616   lives_widget_show_all(insertw->insert_dialog);
1617 
1618   return insertw;
1619 }
1620 
1621 
trash_rb(LiVESButtonBox * parent)1622 LiVESWidget *trash_rb(LiVESButtonBox *parent) {
1623   /// parent should be a bbox
1624   LiVESWidget *rb = NULL;
1625 
1626   if (check_for_executable(&capable->has_gio, EXEC_GIO)) {
1627     LiVESSList *rb_group = NULL;
1628     LiVESWidget *vbox, *hbox;
1629     char *tmp, *tmp2;
1630 
1631     hbox = lives_hbox_new(FALSE, 0);
1632     vbox = lives_vbox_new(FALSE, 0);
1633     lives_box_pack_start(LIVES_BOX(hbox), vbox, FALSE, FALSE, widget_opts.packing_width);
1634 
1635     widget_opts.expand = LIVES_EXPAND_DEFAULT_WIDTH;
1636     rb = lives_standard_radio_button_new((tmp = (_("Send to Trash"))), &rb_group,
1637                                          LIVES_BOX(vbox), (tmp2 = (H_("Send deleted items to filesystem Trash\n"
1638                                              "instead of erasing them permanently"))));
1639     lives_free(tmp); lives_free(tmp2);
1640 
1641     rb = lives_standard_radio_button_new((tmp = (_("Delete"))), &rb_group, LIVES_BOX(vbox),
1642                                          (tmp2 = (H_("Permanently erase items from the disk"))));
1643 
1644     lives_free(tmp); lives_free(tmp2);
1645     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1646 
1647     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rb), !prefs->pref_trash);
1648 
1649     lives_signal_sync_connect(LIVES_GUI_OBJECT(rb), LIVES_WIDGET_ACTIVATE_SIGNAL,
1650                               LIVES_GUI_CALLBACK(toggle_sets_pref), PREF_PREF_TRASH);
1651 
1652     lives_box_pack_start(LIVES_BOX(parent), hbox, FALSE, FALSE, 0);
1653     lives_button_box_make_first(LIVES_BUTTON_BOX(parent), hbox);
1654   }
1655   return rb;
1656 }
1657 
1658 static LiVESResponseType filtresp;
1659 static char *rec_text = NULL, *rem_text = NULL, *leave_text = NULL;
1660 
filt_cb_toggled(LiVESWidget * cb,lives_file_dets_t * filedets)1661 static void filt_cb_toggled(LiVESWidget *cb, lives_file_dets_t *filedets) {
1662   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(cb))) {
1663     if (filedets->widgets[1]) {
1664       lives_widget_set_sensitive(filedets->widgets[1], TRUE);
1665       if (lives_toggle_button_get_active(filedets->widgets[1]))
1666         lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), rec_text);
1667       else
1668         lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), rem_text);
1669     } else
1670       lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), rem_text);
1671   } else {
1672     if (filedets->widgets[1]) {
1673       lives_widget_set_sensitive(filedets->widgets[1], FALSE);
1674     }
1675     lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), leave_text);
1676   }
1677 }
1678 
filt_sw_toggled(LiVESWidget * sw,lives_file_dets_t * filedets)1679 static void filt_sw_toggled(LiVESWidget *sw, lives_file_dets_t *filedets) {
1680   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(sw)))
1681     lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), rec_text);
1682   else
1683     lives_label_set_text(LIVES_LABEL(filedets->widgets[8]), rem_text);
1684 }
1685 
filt_all_toggled(LiVESWidget * cb,LiVESList * list)1686 static void filt_all_toggled(LiVESWidget *cb, LiVESList *list) {
1687   lives_file_dets_t *filedets;
1688   boolean act = lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(cb));
1689   for (; list && list->data; list = list->next) {
1690     filedets = (lives_file_dets_t *)(list->data);
1691     lives_toggle_button_set_active(filedets->widgets[0], act);
1692   }
1693 }
1694 
filt_reset_clicked(LiVESWidget * layout,LiVESWidget * rbut)1695 static void filt_reset_clicked(LiVESWidget *layout, LiVESWidget *rbut) {
1696   LiVESList *list, *xlist;
1697   LiVESWidget *cb =
1698     (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), "cb");
1699   int ptype;
1700   lives_file_dets_t *filedets;
1701 
1702   if (!cb) return;
1703 
1704   ptype = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), "ptype"));
1705   xlist = list = (LiVESList *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), "list");
1706 
1707   switch (ptype) {
1708   case 0:
1709     for (; xlist && xlist->data; xlist = xlist->next) {
1710       filedets = (lives_file_dets_t *)(xlist->data);
1711       lives_toggle_button_set_active(filedets->widgets[1], TRUE);
1712     }
1713   // fall through
1714   case 1:
1715     if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(cb)))
1716       lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(cb), TRUE);
1717     else
1718       filt_all_toggled(cb, list);
1719     break;
1720   case 2:
1721     if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(cb)))
1722       lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(cb), FALSE);
1723     else
1724       filt_all_toggled(cb, list);
1725     break;
1726   default: break;
1727   }
1728 }
1729 
filtc_response(LiVESWidget * w,LiVESResponseType resp,livespointer data)1730 static boolean filtc_response(LiVESWidget *w, LiVESResponseType resp, livespointer data) {
1731   filtresp = resp;
1732   return TRUE;
1733 }
1734 
1735 #define NMLEN_MAX 33
fill_filt_section(LiVESList ** listp,int pass,int type,LiVESWidget * layout)1736 static boolean fill_filt_section(LiVESList **listp, int pass, int type, LiVESWidget *layout) {
1737   LiVESList *list = (LiVESList *)*listp;
1738   lives_file_dets_t *filedets;
1739   LiVESWidget *dialog = NULL;
1740   LiVESWidget *hbox;
1741   LiVESWidget *cb = NULL;
1742 
1743   char *txt, *dtxt;
1744   boolean needs_recheck = FALSE;
1745 
1746   if (!pass) widget_opts.mnemonic_label = FALSE;
1747 
1748   if (!list->data) {
1749     if (!pass) {
1750       txt = lives_strdup_printf("  - %s -  ",
1751                                 mainw->string_constants[LIVES_STRING_CONSTANT_NONE]);
1752       widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1753       widget_opts.justify = LIVES_JUSTIFY_CENTER;
1754       lives_layout_add_label(LIVES_LAYOUT(layout), txt, FALSE);
1755       widget_opts.justify = LIVES_JUSTIFY_DEFAULT;;
1756       widget_opts.expand = LIVES_EXPAND_DEFAULT;
1757       lives_free(txt);
1758       widget_opts.mnemonic_label = TRUE;
1759     }
1760     return FALSE;
1761   }
1762   if (!pass) {
1763     int woat = widget_opts.apply_theme;
1764     int woph = widget_opts.packing_height;
1765 
1766     if (!rec_text) rec_text = (_("Recover"));
1767     if (!rem_text) rem_text = (_("Delete"));
1768     if (!leave_text) leave_text = (_("Leave"));
1769 
1770     dialog = lives_widget_get_toplevel(layout);
1771 
1772     widget_opts.apply_theme = 2;
1773     hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
1774 
1775     //widget_opts.expand = LIVES_EXPAND_NONE;
1776 
1777     // do this to counter effect of setting margin
1778     widget_opts.packing_height = 0;
1779     cb = lives_standard_check_button_new(_("All"), type != 2, LIVES_BOX(hbox), NULL);
1780     widget_opts.packing_height = woph;
1781     lives_widget_set_margin(cb, widget_opts.border_width >> 1);
1782     lives_box_set_child_packing(LIVES_BOX(hbox), cb, FALSE, FALSE, widget_opts.packing_width >> 1,
1783                                 LIVES_PACK_START);
1784 
1785     lives_widget_set_sensitive(cb, FALSE);
1786     //set_child_alt_colour(hbox, FALSE);
1787     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), "cb", (livespointer)cb);
1788 
1789     if (!type) {
1790       widget_opts.justify = LIVES_JUSTIFY_CENTER;
1791       lives_layout_add_label(LIVES_LAYOUT(layout), _("Action"), TRUE);
1792       widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1793     }
1794 
1795     lives_layout_add_label(LIVES_LAYOUT(layout), _("Name"), TRUE);
1796     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1797     lives_layout_add_label(LIVES_LAYOUT(layout), _("Size"), TRUE);
1798     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1799     lives_layout_add_label(LIVES_LAYOUT(layout), _("Modified Date"), TRUE);
1800     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1801     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1802     widget_opts.justify = LIVES_JUSTIFY_CENTER;
1803     lives_layout_add_label(LIVES_LAYOUT(layout), _("Details"), TRUE);
1804     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1805     widget_opts.expand = LIVES_EXPAND_DEFAULT;
1806     widget_opts.apply_theme = woat;
1807     lives_layout_add_separator(LIVES_LAYOUT(layout), FALSE);
1808   }
1809 
1810   while (list->data) {
1811     // put from recover subdir
1812     filedets = (lives_file_dets_t *)(list->data);
1813     if (!pass) {
1814       hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
1815 
1816       filedets->widgets[0] = lives_standard_check_button_new("", type != 2, LIVES_BOX(hbox), NULL);
1817       filedets->widgets[8] = widget_opts.last_label;
1818 
1819       if (!type) {
1820         hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1821         filedets->widgets[1] = lives_standard_switch_new(NULL, TRUE, LIVES_BOX(hbox), NULL);
1822         lives_signal_sync_connect(LIVES_GUI_OBJECT(filedets->widgets[1]), LIVES_WIDGET_TOGGLED_SIGNAL,
1823                                   LIVES_GUI_CALLBACK(filt_sw_toggled), (livespointer)filedets);
1824       } else filedets->widgets[1] = NULL;
1825 
1826       lives_signal_sync_connect(LIVES_GUI_OBJECT(filedets->widgets[0]), LIVES_WIDGET_TOGGLED_SIGNAL,
1827                                 LIVES_GUI_CALLBACK(filt_cb_toggled), (livespointer)filedets);
1828 
1829       filt_cb_toggled(filedets->widgets[0], filedets);
1830 
1831       txt = lives_pad_ellipsize(filedets->name, NMLEN_MAX, LIVES_ALIGN_START, LIVES_ELLIPSIZE_MIDDLE);
1832       lives_layout_add_label(LIVES_LAYOUT(layout), txt, TRUE);
1833       if (txt != filedets->name) {
1834         lives_free(txt);
1835         lives_widget_set_tooltip_text(widget_opts.last_label, filedets->name);
1836       }
1837       lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1838       hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1839 
1840       filedets->widgets[2] = lives_standard_label_new(NULL);
1841       lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[2]);
1842       lives_widget_hide(filedets->widgets[2]);
1843       lives_widget_set_no_show_all(filedets->widgets[2], TRUE);
1844 
1845       if (filedets->size == -1) {
1846         filedets->widgets[3] = lives_spinner_new();
1847         if (filedets->widgets[3]) {
1848           lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[3]);
1849           lives_spinner_start(LIVES_SPINNER(filedets->widgets[3]));
1850         } else filedets->widgets[3] = filedets->widgets[2];
1851       } else filedets->widgets[3] = filedets->widgets[2];
1852     }
1853 
1854     if (filedets->widgets[3]) {
1855       if (filedets->size != -1) {
1856         if (filedets->widgets[3] != filedets->widgets[2]) {
1857           lives_spinner_stop(LIVES_SPINNER(filedets->widgets[3]));
1858           lives_widget_hide(filedets->widgets[3]);
1859           lives_widget_set_no_show_all(filedets->widgets[3], TRUE);
1860         }
1861         lives_widget_set_no_show_all(filedets->widgets[2], FALSE);
1862         lives_widget_show_all(filedets->widgets[2]);
1863 
1864         if (filedets->size == -2) {
1865           lives_label_set_text(LIVES_LABEL(filedets->widgets[2]), "????");
1866         }
1867         if (filedets->size > 0) {
1868           txt = lives_format_storage_space_string(filedets->size);
1869           lives_label_set_text(LIVES_LABEL(filedets->widgets[2]), txt);
1870           lives_free(txt);
1871         }
1872         filedets->widgets[3] = NULL;
1873       } else needs_recheck = TRUE;
1874     }
1875 
1876     if (!pass) {
1877       lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1878       hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1879       filedets->widgets[4] = lives_standard_label_new(NULL);
1880       lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[4]);
1881       lives_widget_hide(filedets->widgets[4]);
1882       lives_widget_set_no_show_all(filedets->widgets[4], TRUE);
1883 
1884       if (!filedets->extra_details) {
1885         filedets->widgets[5] = lives_spinner_new();
1886         if (filedets->widgets[5]) {
1887           lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[5]);
1888           lives_spinner_start(LIVES_SPINNER(filedets->widgets[5]));
1889         } else filedets->widgets[5] = filedets->widgets[4];
1890       } else filedets->widgets[5] = filedets->widgets[4];
1891 
1892       lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
1893       hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1894       filedets->widgets[6] = lives_standard_label_new(NULL);
1895       lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[6]);
1896       lives_widget_hide(filedets->widgets[6]);
1897       lives_widget_set_no_show_all(filedets->widgets[6], TRUE);
1898 
1899       if (!filedets->extra_details) {
1900         filedets->widgets[7] = lives_spinner_new();
1901         if (filedets->widgets[7]) {
1902           widget_opts.justify = LIVES_JUSTIFY_CENTER;
1903           widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1904           lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[7]);
1905           widget_opts.expand = LIVES_EXPAND_DEFAULT;
1906           widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1907           lives_spinner_start(LIVES_SPINNER(filedets->widgets[7]));
1908         } else filedets->widgets[7] = filedets->widgets[6];
1909       } else filedets->widgets[7] = filedets->widgets[6];
1910     }
1911 
1912     if (filedets->widgets[5]) {
1913       if (filedets->extra_details) {
1914         if (filedets->widgets[5] != filedets->widgets[4]) {
1915           lives_spinner_stop(LIVES_SPINNER(filedets->widgets[5]));
1916           lives_widget_hide(filedets->widgets[5]);
1917           lives_widget_set_no_show_all(filedets->widgets[5], TRUE);
1918         }
1919         lives_widget_set_no_show_all(filedets->widgets[4], FALSE);
1920         lives_widget_show_all(filedets->widgets[4]);
1921 
1922         if (!filedets->mtime_sec) {
1923           lives_label_set_text(LIVES_LABEL(filedets->widgets[4]), "????");
1924         } else {
1925           txt = lives_datetime(filedets->mtime_sec, TRUE);
1926           dtxt = lives_datetime_rel(txt);
1927           lives_label_set_text(LIVES_LABEL(filedets->widgets[4]), dtxt);
1928           if (dtxt != txt) lives_free(dtxt);
1929           lives_free(txt);
1930         }
1931 
1932         if (filedets->widgets[7] != filedets->widgets[6]) {
1933           lives_spinner_stop(LIVES_SPINNER(filedets->widgets[7]));
1934           lives_widget_hide(filedets->widgets[7]);
1935           lives_widget_set_no_show_all(filedets->widgets[7], TRUE);
1936         }
1937         lives_widget_set_no_show_all(filedets->widgets[6], FALSE);
1938         lives_widget_show_all(filedets->widgets[6]);
1939 
1940         if ((filedets->type & LIVES_FILE_TYPE_MASK) == LIVES_FILE_TYPE_UNKNOWN) {
1941           lives_label_set_text(LIVES_LABEL(filedets->widgets[6]), "????");
1942         } else {
1943           if (LIVES_FILE_IS_FILE(filedets->type))
1944             txt = lives_strdup_printf(_("\tFile\t\t:\t%s"),
1945                                       filedets->extra_details ? filedets->extra_details : " - ");
1946           else if (LIVES_FILE_IS_DIRECTORY(filedets->type))
1947             txt = lives_strdup_printf(_("\tDirectory\t\t:\t%s"),
1948                                       filedets->extra_details ? filedets->extra_details : " - ");
1949           else
1950             txt = lives_strdup_printf(_("\t????????\t\t:\t%s"),
1951                                       filedets->extra_details ? filedets->extra_details : " - ");
1952           lives_label_set_text(LIVES_LABEL(filedets->widgets[6]), txt);
1953           lives_free(txt);
1954         }
1955         filedets->widgets[5] = NULL;
1956       } else needs_recheck = TRUE;
1957     }
1958 
1959     if (!pass) {
1960       lives_widget_show_all(dialog);
1961       do {
1962         lives_widget_context_update();
1963         //lives_widget_process_updates(dialog);
1964         lives_nanosleep(100);
1965       } while (!list->next && filtresp == LIVES_RESPONSE_NONE);
1966     }
1967     if (filtresp != LIVES_RESPONSE_NONE) goto ffxdone;
1968     list = list->next;
1969   }
1970   if (cb) {
1971     lives_signal_sync_connect(LIVES_GUI_OBJECT(cb), LIVES_WIDGET_TOGGLED_SIGNAL,
1972                               LIVES_GUI_CALLBACK(filt_all_toggled), (livespointer)*listp);
1973     lives_widget_set_sensitive(cb, TRUE);
1974   }
1975 ffxdone:
1976   widget_opts.mnemonic_label = TRUE;
1977   return needs_recheck;
1978 }
1979 
1980 
filter_cleanup(const char * trashdir,LiVESList ** rec_list,LiVESList ** rem_list,LiVESList ** left_list)1981 LiVESResponseType filter_cleanup(const char *trashdir, LiVESList **rec_list, LiVESList **rem_list,
1982                                  LiVESList **left_list) {
1983   LiVESWidget *dialog;
1984   LiVESWidget *layout, *layout_rec, *layout_rem, *layout_leave;
1985   LiVESWidget *top_vbox;
1986   LiVESWidget *scrolledwindow;
1987   LiVESWidget *cancelb;
1988   LiVESWidget *resetb = NULL;
1989   LiVESWidget *accb;
1990   LiVESWidget *vbox;
1991   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1992 
1993   int winsize_h = GUI_SCREEN_WIDTH - SCR_WIDTH_SAFETY;
1994   int winsize_v = GUI_SCREEN_HEIGHT - SCR_HEIGHT_SAFETY * 2;
1995   int rec_recheck, rem_recheck, leave_recheck;
1996   int pass = 0;
1997   int woat = widget_opts.apply_theme;
1998   int wopw = widget_opts.packing_width;
1999 
2000   char *txt;
2001 
2002   // get size, type (dir or file), nitems, extra_dets
2003   // cr dat, mod date
2004 
2005   filtresp = LIVES_RESPONSE_NONE;
2006 
2007   dialog = lives_standard_dialog_new(_("Disk Cleanup"), FALSE, winsize_h, winsize_v);
2008   lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
2009   lives_widget_set_maximum_size(dialog, winsize_h, winsize_v);
2010 
2011   if ((*rec_list && (*rec_list)->data) || (*rem_list && (*rem_list)->data)
2012       || (*left_list && (*left_list)->data)) {
2013     LiVESWidget *bbox = lives_dialog_get_action_area(LIVES_DIALOG(dialog));
2014     cancelb = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
2015               LIVES_STOCK_CANCEL, NULL, LIVES_RESPONSE_CANCEL);
2016 
2017     lives_widget_add_accelerator(cancelb, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
2018                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
2019 
2020     resetb = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
2021              LIVES_STOCK_UNDO, _("_Reset"), LIVES_RESPONSE_NONE);
2022     lives_widget_set_sensitive(resetb, FALSE);
2023 
2024     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2025     accb = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
2026            LIVES_STOCK_GO_FORWARD, _("_Accept and Continue"), LIVES_RESPONSE_ACCEPT);
2027     widget_opts.expand = LIVES_EXPAND_DEFAULT;
2028     lives_widget_set_sensitive(accb, FALSE);
2029 
2030     trash_rb(LIVES_BUTTON_BOX(bbox));
2031     lives_button_box_set_layout(LIVES_BUTTON_BOX(bbox), LIVES_BUTTONBOX_CENTER);
2032   } else {
2033     accb = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
2034            LIVES_STOCK_CLOSE, _("_Close Window"),
2035            LIVES_RESPONSE_OK);
2036     lives_widget_add_accelerator(accb, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
2037                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
2038     lives_button_grab_default_special(accb);
2039   }
2040 
2041   lives_signal_sync_connect(dialog, LIVES_WIDGET_RESPONSE_SIGNAL,
2042                             LIVES_GUI_CALLBACK(filtc_response), NULL);
2043 
2044   top_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
2045 
2046   layout = lives_layout_new(LIVES_BOX(top_vbox));
2047   lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
2048   txt = lives_strdup_printf(_("Analysis of directory: %s"), prefs->workdir);
2049   lives_layout_add_label(LIVES_LAYOUT(layout), txt, FALSE);
2050   lives_free(txt);
2051   lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
2052 
2053   vbox = lives_vbox_new(FALSE, 0);
2054   widget_opts.apply_theme = 0;
2055   scrolledwindow = lives_standard_scrolled_window_new(winsize_h, winsize_v, vbox);
2056   widget_opts.apply_theme = woat;
2057   lives_box_pack_start(LIVES_BOX(top_vbox), scrolledwindow, TRUE, TRUE, widget_opts.packing_height);
2058 
2059   /// items for recovery /////////////////////////
2060 
2061   layout_rec = lives_layout_new(LIVES_BOX(vbox));
2062   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2063   widget_opts.justify = LIVES_JUSTIFY_CENTER;
2064   lives_layout_add_label(LIVES_LAYOUT(layout_rec), _("Possibly Recoverable Clips"), FALSE);
2065   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2066   widget_opts.expand = LIVES_EXPAND_DEFAULT;
2067   lives_layout_add_fill(LIVES_LAYOUT(layout_rec), FALSE);
2068 
2069   lives_widget_show_all(dialog);
2070 
2071   do {
2072     lives_widget_process_updates(dialog);
2073     if (!*rec_list && filtresp == LIVES_RESPONSE_NONE) lives_nanosleep(1000);
2074   } while (!*rec_list && filtresp == LIVES_RESPONSE_NONE);
2075 
2076   if (filtresp != LIVES_RESPONSE_NONE) goto harlem_shuffle;
2077 
2078   rec_recheck = fill_filt_section(rec_list, pass, 0, layout_rec);
2079   lives_layout_add_fill(LIVES_LAYOUT(layout_rec), FALSE);
2080 
2081   add_hsep_to_box(LIVES_BOX(vbox));
2082 
2083   layout_rem = lives_layout_new(LIVES_BOX(vbox));
2084   widget_opts.packing_width = wopw;
2085   lives_layout_add_fill(LIVES_LAYOUT(layout_rem), FALSE);
2086   lives_layout_add_fill(LIVES_LAYOUT(layout_rem), FALSE);
2087   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2088   widget_opts.justify = LIVES_JUSTIFY_CENTER;
2089   lives_layout_add_label(LIVES_LAYOUT(layout_rem), _("Items for Automatic Removal"), FALSE);
2090   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2091   widget_opts.expand = LIVES_EXPAND_DEFAULT;
2092   lives_layout_add_fill(LIVES_LAYOUT(layout_rem), FALSE);
2093 
2094   lives_widget_show_all(dialog);
2095 
2096   do {
2097     lives_widget_process_updates(dialog);
2098     if (!*rem_list && filtresp == LIVES_RESPONSE_NONE) lives_nanosleep(1000);
2099   } while (!*rem_list && filtresp == LIVES_RESPONSE_NONE);
2100 
2101   if (filtresp != LIVES_RESPONSE_NONE) goto harlem_shuffle;
2102 
2103   rem_recheck = fill_filt_section(rem_list, pass, 1, layout_rem);
2104   lives_layout_add_fill(LIVES_LAYOUT(layout_rem), FALSE);
2105 
2106   add_hsep_to_box(LIVES_BOX(vbox));
2107 
2108   /// items for manual removal
2109   layout_leave = lives_layout_new(LIVES_BOX(vbox));
2110   lives_layout_add_fill(LIVES_LAYOUT(layout_leave), FALSE);
2111   lives_layout_add_fill(LIVES_LAYOUT(layout_leave), FALSE);
2112   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2113   widget_opts.justify = LIVES_JUSTIFY_CENTER;
2114   lives_layout_add_label(LIVES_LAYOUT(layout_leave), _("Items for Manual Removal"), FALSE);
2115   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2116   widget_opts.expand = LIVES_EXPAND_DEFAULT;
2117   lives_layout_add_fill(LIVES_LAYOUT(layout_leave), FALSE);
2118 
2119   lives_widget_show_all(dialog);
2120 
2121   do {
2122     lives_widget_process_updates(dialog);
2123     if (!*left_list && filtresp == LIVES_RESPONSE_NONE) lives_nanosleep(1000);
2124   } while (!*left_list && filtresp == LIVES_RESPONSE_NONE);
2125 
2126   if (filtresp != LIVES_RESPONSE_NONE) goto harlem_shuffle;
2127 
2128   leave_recheck = fill_filt_section(left_list, pass, 2, layout_leave);
2129   lives_layout_add_fill(LIVES_LAYOUT(layout_leave), FALSE);
2130 
2131 
2132   if (resetb) {
2133     /// reset button
2134     if (!pass) {
2135       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_rec), "list", *rec_list);
2136       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_rec), "ptype",
2137                                    LIVES_INT_TO_POINTER(0));
2138       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_rem), "list", *rem_list);
2139       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_rem), "ptype",
2140                                    LIVES_INT_TO_POINTER(1));
2141       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_leave), "list", *left_list);
2142       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout_leave), "ptype",
2143                                    LIVES_INT_TO_POINTER(2));
2144 
2145       lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(resetb), LIVES_WIDGET_CLICKED_SIGNAL,
2146                                         LIVES_GUI_CALLBACK(filt_reset_clicked), layout_rec);
2147       lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(resetb), LIVES_WIDGET_CLICKED_SIGNAL,
2148                                         LIVES_GUI_CALLBACK(filt_reset_clicked), layout_rem);
2149       lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(resetb), LIVES_WIDGET_CLICKED_SIGNAL,
2150                                         LIVES_GUI_CALLBACK(filt_reset_clicked), layout_leave);
2151 
2152       lives_widget_set_sensitive(resetb, TRUE);
2153       lives_widget_set_sensitive(accb, TRUE);
2154       lives_button_grab_default_special(accb);
2155     }
2156   }
2157 
2158   /////////
2159   while (filtresp == LIVES_RESPONSE_NONE && (rec_recheck || rem_recheck || leave_recheck)) {
2160     ++pass;
2161     if (rec_recheck) rec_recheck = fill_filt_section(rec_list, pass, 0, layout_rec);
2162     if (rem_recheck) rem_recheck = fill_filt_section(rem_list, pass, 1, layout_rem);
2163     if (leave_recheck) leave_recheck = fill_filt_section(left_list, pass, 2, layout_leave);
2164     lives_widget_process_updates(dialog);
2165     if (filtresp == LIVES_RESPONSE_NONE && (rec_recheck || rem_recheck || leave_recheck)) lives_nanosleep(100);
2166   };
2167 
2168   while (filtresp == LIVES_RESPONSE_NONE) lives_dialog_run(LIVES_DIALOG(dialog));
2169 
2170 harlem_shuffle:
2171 
2172   if (filtresp != LIVES_RESPONSE_CANCEL && filtresp != LIVES_RESPONSE_OK) {
2173     // we need to shuffle the lists around before destroying the dialog; caller will move
2174     // actual pointer files
2175     LiVESList *list, *listnext;
2176     lives_file_dets_t *filedets;
2177     lives_widget_hide(dialog);
2178     lives_widget_process_updates(dialog);
2179 
2180     for (pass = 0; pass < 3; pass++) {
2181       if (!pass) list = *rec_list;
2182       else if (pass == 1) list = *rem_list;
2183       else list = *left_list;
2184       for (; list && list->data; list = listnext) {
2185         listnext = list->next;
2186         // entries can move to rem_list or left_list
2187         // we no longer care about type, so the field will be reused to
2188         // store the origin list number
2189         // for this we will re-use pass, 0 -> rec_list, 1 -> rem_list, 2 -> left_list
2190         filedets = (lives_file_dets_t *)list->data;
2191         if (filedets->type & LIVES_FILE_TYPE_FLAG_SPECIAL) continue;
2192         filedets->type = ((uint64_t)pass | (uint64_t)LIVES_FILE_TYPE_FLAG_SPECIAL);
2193         if (!pass || pass == 2) {
2194           if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(filedets->widgets[0]))) {
2195             if (pass == 2 || !lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(filedets->widgets[1]))) {
2196               // move into delete from recover or leave
2197               if (list->prev) list->prev->next = list->next;
2198               if (list->next) list->next->prev = list->prev;
2199               list->prev = NULL;
2200               if (list == *rec_list) *rec_list = list->next;
2201               else if (list == *left_list) *left_list = list->next;
2202               list->next = *rem_list;
2203               (*rem_list)->prev = list;
2204               *rem_list = list;
2205             }
2206           }
2207         }
2208         if (pass != 2) {
2209           if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(filedets->widgets[0]))) {
2210             // move to leave, from rec or rem
2211             if (list->prev) list->prev->next = list->next;
2212             if (list->next) list->next->prev = list->prev;
2213             list->prev = NULL;
2214             if (list == *rec_list) *rec_list = list->next;
2215             else if (list == *rem_list) *rem_list = list->next;
2216             list->next = *left_list;
2217             (*left_list)->prev = list;
2218             *left_list = list;
2219 	    // *INDENT-OFF*
2220 	  }}}}}
2221   // *INDENT-ON*
2222   lives_widget_destroy(dialog);
2223   //lives_widget_context_update();
2224   return filtresp;
2225 }
2226 
2227 
create_opensel_dialog(int frames,double fps)2228 LiVESWidget *create_opensel_dialog(int frames, double fps) {
2229   LiVESWidget *opensel_dialog;
2230   LiVESWidget *dialog_vbox;
2231   LiVESWidget *vbox;
2232   LiVESWidget *table;
2233   LiVESWidget *label;
2234   LiVESWidget *spinbutton;
2235   LiVESWidget *cancelbutton;
2236   LiVESWidget *okbutton;
2237 
2238   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
2239 
2240   double tottime = 0.;
2241 
2242   char *text;
2243 
2244   if (fps > 0.) tottime = (double)frames / fps;
2245 
2246   opensel_dialog = lives_standard_dialog_new(_("Open Selection"), FALSE, -1, -1);
2247 
2248   lives_window_add_accel_group(LIVES_WINDOW(opensel_dialog), accel_group);
2249 
2250   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(opensel_dialog));
2251 
2252   vbox = lives_vbox_new(FALSE, 0);
2253   lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox, TRUE, TRUE, 0);
2254   lives_widget_set_size_request(LIVES_WIDGET(opensel_dialog), RFX_WINSIZE_H, RFX_WINSIZE_V);
2255 
2256   table = lives_table_new(2, 3, FALSE);
2257   lives_table_set_column_homogeneous(LIVES_TABLE(table), FALSE);
2258   lives_box_pack_start(LIVES_BOX(vbox), table, FALSE, TRUE, widget_opts.packing_height * 4);
2259 
2260   lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height * 4);
2261 
2262   label = lives_standard_label_new(_("Selection start time (sec)"));
2263   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 0, 1,
2264                      (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2265                      (LiVESAttachOptions)(0), 0, 0);
2266   lives_widget_set_halign(label, LIVES_ALIGN_END);
2267 
2268   if (frames > 0 && fps > 0.)
2269     text = lives_strdup_printf(_("[ maximum =  %.2f ]"), tottime);
2270   else text = lives_strdup("");
2271   label = lives_standard_label_new(text);
2272   lives_free(text);
2273 
2274   lives_table_attach(LIVES_TABLE(table), label, 2, 3, 0, 1,
2275                      (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2276                      (LiVESAttachOptions)(0), 0, 0);
2277   lives_widget_set_halign(label, LIVES_ALIGN_START);
2278 
2279   label = lives_standard_label_new(_("Number of frames to open"));
2280   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 1, 2,
2281                      (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2282                      (LiVESAttachOptions)(0), 0, 0);
2283   lives_widget_set_halign(label, LIVES_ALIGN_END);
2284 
2285   if (frames > 0)
2286     text = lives_strdup_printf(_("[ maximum =  %d ]"), frames);
2287   else text = lives_strdup("");
2288 
2289   label = lives_standard_label_new(text);
2290   lives_free(text);
2291 
2292   lives_table_attach(LIVES_TABLE(table), label, 2, 3, 1, 2,
2293                      (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2294                      (LiVESAttachOptions)(0), 0, 0);
2295   lives_widget_set_halign(label, LIVES_ALIGN_START);
2296 
2297   spinbutton = lives_standard_spin_button_new(NULL, mainw->fx1_val, 0., tottime, 1., 1., 2, NULL, NULL);
2298   lives_widget_set_halign(spinbutton, LIVES_ALIGN_START);
2299 
2300   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2301                                   LIVES_GUI_CALLBACK(on_spin_value_changed),
2302                                   LIVES_INT_TO_POINTER(1));
2303 
2304   lives_table_attach(LIVES_TABLE(table), spinbutton, 1, 2, 0, 1,
2305                      (LiVESAttachOptions)(LIVES_FILL),
2306                      (LiVESAttachOptions)(0), widget_opts.packing_height * 2 + 2, 0);
2307 
2308   spinbutton = lives_standard_spin_button_new(NULL, (double)mainw->fx2_val, 1., (double)frames, 1., 1., 0, NULL, NULL);
2309   lives_widget_set_halign(spinbutton, LIVES_ALIGN_START);
2310 
2311   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2312                                   LIVES_GUI_CALLBACK(on_spin_value_changed),
2313                                   LIVES_INT_TO_POINTER(2));
2314 
2315   lives_table_attach(LIVES_TABLE(table), spinbutton, 1, 2, 1, 2,
2316                      (LiVESAttachOptions)(LIVES_FILL),
2317                      (LiVESAttachOptions)(0), widget_opts.packing_height * 2 + 2, 0);
2318 
2319   widget_add_preview(opensel_dialog, LIVES_BOX(vbox), LIVES_BOX(vbox), LIVES_BOX(vbox), LIVES_PREVIEW_TYPE_RANGE);
2320 
2321   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(opensel_dialog), LIVES_STOCK_CANCEL, NULL,
2322                  LIVES_RESPONSE_CANCEL);
2323 
2324   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
2325                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
2326 
2327   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(opensel_dialog), LIVES_STOCK_OK, NULL,
2328              LIVES_RESPONSE_OK);
2329 
2330   lives_button_grab_default_special(okbutton);
2331 
2332   lives_signal_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2333                        LIVES_GUI_CALLBACK(on_cancel_opensel_clicked), NULL);
2334 
2335   lives_signal_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2336                        LIVES_GUI_CALLBACK(on_opensel_range_ok_clicked), NULL);
2337 
2338   lives_window_set_resizable(LIVES_WINDOW(opensel_dialog), TRUE);
2339 
2340   if (prefs->open_maximised || prefs->fileselmax) {
2341     lives_window_maximize(LIVES_WINDOW(opensel_dialog));
2342   }
2343 
2344   lives_widget_show_all(opensel_dialog);
2345 
2346   return opensel_dialog;
2347 }
2348 
2349 
create_location_dialog(void)2350 _entryw *create_location_dialog(void) {
2351   LiVESWidget *dialog_vbox;
2352   LiVESWidget *cancelbutton;
2353   LiVESWidget *okbutton;
2354   LiVESWidget *label;
2355   LiVESWidget *checkbutton;
2356   LiVESWidget *hbox;
2357 
2358   _entryw *locw = (_entryw *)(lives_malloc(sizeof(_entryw)));
2359 
2360   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
2361 
2362   char *title, *tmp, *tmp2;
2363 
2364   title = (_("Open Location"));
2365 
2366   locw->dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
2367   lives_signal_handlers_disconnect_by_func(locw->dialog, LIVES_GUI_CALLBACK(return_true), NULL);
2368 
2369   lives_free(title);
2370 
2371   lives_window_add_accel_group(LIVES_WINDOW(locw->dialog), accel_group);
2372 
2373   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(locw->dialog));
2374 
2375   widget_opts.justify = LIVES_JUSTIFY_CENTER;
2376 
2377   label = lives_standard_label_new(
2378             _("\n\nTo open a stream, you must make sure that you have the correct libraries "
2379               "compiled in mplayer (or mpv).\n"
2380               "Also make sure you have set your bandwidth in Preferences|Streaming\n\n"));
2381 
2382   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2383 
2384   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, 0);
2385 
2386   hbox = lives_hbox_new(FALSE, 0);
2387   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 2);
2388 
2389   locw->entry = lives_standard_entry_new(_("URL : "), "", LONG_ENTRY_WIDTH, 32768, LIVES_BOX(hbox), NULL);
2390 
2391   add_fill_to_box(LIVES_BOX(hbox));
2392 
2393   hbox = lives_hbox_new(FALSE, 0);
2394   checkbutton = lives_standard_check_button_new((tmp = (_("Do not send bandwidth information"))),
2395                 prefs->no_bandwidth, LIVES_BOX(hbox),
2396                 (tmp2 = (_("Try this setting if you are having problems getting a stream"))));
2397 
2398   lives_free(tmp); lives_free(tmp2);
2399 
2400   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height * 2);
2401 
2402   lives_signal_sync_connect(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2403                             LIVES_GUI_CALLBACK(on_boolean_toggled),
2404                             &prefs->no_bandwidth);
2405 
2406   add_deinterlace_checkbox(LIVES_BOX(dialog_vbox));
2407 
2408   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(locw->dialog), LIVES_STOCK_CANCEL, NULL,
2409                  LIVES_RESPONSE_CANCEL);
2410 
2411   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(locw->dialog), LIVES_STOCK_OK, NULL,
2412              LIVES_RESPONSE_OK);
2413   lives_button_grab_default_special(okbutton);
2414 
2415   lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2416                             LIVES_GUI_CALLBACK(lives_general_button_clicked), locw);
2417 
2418   lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2419                             LIVES_GUI_CALLBACK(on_location_select), NULL);
2420 
2421   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
2422                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
2423 
2424   lives_widget_show_all(locw->dialog);
2425 
2426   return locw;
2427 }
2428 
2429 
mkszlabel(const char * set,ssize_t size,int ccount,int lcount)2430 static char *mkszlabel(const char *set, ssize_t size, int ccount, int lcount) {
2431   char *bit1 = lives_strdup_printf(_("Contents of Set %s"), set), *bit2;
2432   char *szstr, *label, *laystr, *clpstr;
2433   if (size < 0) szstr = lives_strdup(_("Calculating..."));
2434   else szstr = lives_format_storage_space_string(size);
2435   if (ccount == -1) clpstr = (_("counting..."));
2436   else clpstr = lives_strdup_printf("%d", ccount);
2437   if (lcount == -1) laystr = (_("counting..."));
2438   else laystr = lives_strdup_printf("%d", lcount);
2439   bit2 = lives_strdup_printf(_("Total size = %s\tclips: %s\tlayouts: %s"), szstr, clpstr, laystr);
2440   label = lives_strdup_printf("%s\n%s\n", bit1, bit2);
2441   lives_free(bit1); lives_free(bit2);
2442   lives_free(laystr); lives_free(clpstr);
2443   return label;
2444 }
2445 
2446 
on_set_exp(LiVESWidget * exp,_entryw * renamew)2447 static void on_set_exp(LiVESWidget * exp, _entryw * renamew) {
2448   lives_proc_thread_t layinfo = NULL, clipsinfo = NULL, sizinfo = NULL;
2449   LiVESList *lists[2];
2450   LiVESList **laylist = &lists[0], **clipslist = &lists[1];
2451 
2452   *laylist = *clipslist = NULL;
2453 
2454   if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2455     widget_opts.use_markup = TRUE;
2456     lives_expander_set_label(LIVES_EXPANDER(exp), _("<b>Show Contents</b>"));
2457     widget_opts.use_markup = FALSE;
2458     if (renamew->layouts_layout) {
2459       lives_widget_destroy(renamew->layouts_layout);
2460       renamew->layouts_layout = NULL;
2461     }
2462     if (renamew->clips_layout) {
2463       lives_widget_destroy(renamew->clips_layout);
2464       renamew->clips_layout = NULL;
2465     }
2466     lives_widget_set_sensitive(renamew->entry, TRUE);
2467     return;
2468   } else {
2469     lives_file_dets_t *filedets;
2470     const char *set = lives_entry_get_text(LIVES_ENTRY(renamew->entry));
2471     LiVESList *list;
2472     ssize_t totsize = -1;
2473     char *txt, *dtxt;
2474     char *setdir = lives_build_path(prefs->workdir, set, NULL);
2475     char *ldirname = lives_build_path(setdir, LAYOUTS_DIRNAME, NULL);
2476     char *ordfilename = lives_build_filename(setdir, CLIP_ORDER_FILENAME, NULL);
2477     int woat = widget_opts.apply_theme;
2478     int lcount = 0, ccount = 0;
2479 
2480     sizinfo = lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)get_dir_size, WEED_SEED_INT64, "s",
2481                                        setdir);
2482 
2483     widget_opts.use_markup = TRUE;
2484     lives_expander_set_label(LIVES_EXPANDER(exp), _("<b>Hide Contents</b>"));
2485     widget_opts.use_markup = FALSE;
2486 
2487     layinfo = dir_to_file_details(laylist, ldirname, NULL, 0);
2488 
2489     clipsinfo =
2490       ordfile_to_file_details(clipslist, ordfilename, prefs->workdir,
2491                               EXTRA_DETAILS_CLIPHDR | EXTRA_DETAILS_DIRSIZE
2492                               | EXTRA_DETAILS_CHECK_MISSING);
2493 
2494     if (lives_proc_thread_check(sizinfo)) totsize = lives_proc_thread_join_int64(sizinfo);
2495     txt = mkszlabel(set, totsize, -1, -1);
2496     lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2497     lives_free(txt);
2498 
2499     lives_free(ldirname); lives_free(ordfilename);
2500 
2501     lives_widget_set_sensitive(renamew->entry, FALSE);
2502 
2503     // layouts
2504     renamew->layouts_layout = lives_layout_new(LIVES_BOX(renamew->exp_vbox));
2505     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2506     widget_opts.justify = LIVES_JUSTIFY_CENTER;
2507     lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), _("Layouts"), FALSE);
2508     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2509     widget_opts.expand = LIVES_EXPAND_DEFAULT;
2510     lives_layout_add_fill(LIVES_LAYOUT(renamew->layouts_layout), FALSE);
2511 
2512     lives_widget_show_all(renamew->expander);
2513 
2514     do {
2515       lives_widget_process_updates(renamew->dialog);
2516       if (!*laylist && lives_expander_get_expanded(LIVES_EXPANDER(exp))) lives_nanosleep(1000);
2517     } while (!*laylist && lives_expander_get_expanded(LIVES_EXPANDER(exp)));
2518 
2519     if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2520 
2521     if (totsize == -1) {
2522       if (lives_proc_thread_check(sizinfo)) totsize = lives_proc_thread_join_int64(sizinfo);
2523       txt = mkszlabel(set, totsize, -1, -1);
2524       lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2525       lives_free(txt);
2526     }
2527 
2528     list = *laylist;
2529     if (!list->data) {
2530       // NONE label
2531       //lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), mainw->string_constants[LIVES_STRING_CONSTANT_NONE], FALSE);
2532       lives_widget_hide(renamew->layouts_layout);
2533       txt = mkszlabel(set, totsize, -1, 0);
2534       lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2535       lives_free(txt);
2536     } else {
2537       widget_opts.apply_theme = 2;
2538       lives_layout_add_row(LIVES_LAYOUT(renamew->layouts_layout));
2539       lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), _("Modified Date"), TRUE);
2540       lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), _("Size"), TRUE);
2541       lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), _("Name"), TRUE);
2542       widget_opts.apply_theme = woat;
2543 
2544       lives_widget_show_all(renamew->layouts_layout);
2545 
2546       while (list->data && lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2547         lcount++;
2548         filedets = (lives_file_dets_t *)(list->data);
2549         do {
2550           // wait for size
2551           lives_widget_process_updates(renamew->dialog);
2552           if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2553             if (!filedets->extra_details) lives_nanosleep(1000);
2554             if (totsize == -1) {
2555               if (lives_proc_thread_check(sizinfo)) {
2556                 totsize = lives_proc_thread_join_int64(sizinfo);
2557                 txt = mkszlabel(set, totsize, -1, lcount);
2558                 lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2559                 lives_free(txt);
2560               }
2561             }
2562           }
2563         } while (!filedets->extra_details && lives_expander_get_expanded(LIVES_EXPANDER(exp)));
2564         if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2565         lives_layout_add_row(LIVES_LAYOUT(renamew->layouts_layout));
2566         txt = lives_datetime(filedets->mtime_sec, TRUE);
2567         dtxt = lives_datetime_rel(txt);
2568         lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), dtxt, TRUE);
2569         if (dtxt != txt) lives_free(dtxt);
2570         lives_free(txt);
2571         txt = lives_format_storage_space_string(filedets->size);
2572         lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), txt, TRUE);
2573         lives_free(txt);
2574         lives_layout_add_label(LIVES_LAYOUT(renamew->layouts_layout), filedets->name, TRUE);
2575         lives_widget_show_all(renamew->expander);
2576         do {
2577           lives_widget_process_updates(renamew->dialog);
2578           if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2579             if (totsize == -1) {
2580               if (lives_proc_thread_check(sizinfo)) {
2581                 totsize = lives_proc_thread_join_int64(sizinfo);
2582                 txt = mkszlabel(set, totsize, -1, lcount);
2583                 lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2584                 lives_free(txt);
2585                 lives_widget_process_updates(renamew->dialog);
2586               }
2587             }
2588           }
2589           if (lives_expander_get_expanded(LIVES_EXPANDER(exp)) && !list->next) lives_nanosleep(1000);
2590         } while (!list->next && lives_expander_get_expanded(LIVES_EXPANDER(exp)));
2591         if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2592         list = list->next;
2593       }
2594     }
2595 
2596     if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2597 
2598     do {
2599       lives_widget_process_updates(renamew->dialog);
2600       if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2601         if (totsize == -1) {
2602           if (lives_proc_thread_check(sizinfo)) {
2603             totsize = lives_proc_thread_join_int64(sizinfo);
2604             txt = mkszlabel(set, totsize, lcount, -1);
2605             lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2606             lives_free(txt);
2607             lives_widget_process_updates(renamew->dialog);
2608           }
2609         }
2610       }
2611       if (!*clipslist && lives_expander_get_expanded(LIVES_EXPANDER(exp))) lives_nanosleep(1000);
2612     } while (!*clipslist && lives_expander_get_expanded(LIVES_EXPANDER(exp)));
2613 
2614     if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2615 
2616     // clips
2617     renamew->clips_layout = lives_layout_new(LIVES_BOX(renamew->exp_vbox));
2618     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
2619     widget_opts.justify = LIVES_JUSTIFY_CENTER;
2620     lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), _("Clips"), FALSE);
2621     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2622     widget_opts.expand = LIVES_EXPAND_DEFAULT;
2623     lives_layout_add_fill(LIVES_LAYOUT(renamew->clips_layout), FALSE);
2624 
2625     list = *clipslist;
2626     if (!list->data) {
2627       // NONE label
2628       lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), mainw->string_constants[LIVES_STRING_CONSTANT_NONE], FALSE);
2629     } else {
2630       int pass = 0;
2631       widget_opts.apply_theme = 2;
2632       lives_layout_add_row(LIVES_LAYOUT(renamew->clips_layout));
2633       lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), _("Modified Date"), TRUE);
2634       lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), _("Size"), TRUE);
2635       lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), _("Details"), TRUE);
2636       widget_opts.apply_theme = woat;
2637 
2638       while (list->data && lives_expander_get_expanded(LIVES_EXPANDER(exp))) {
2639         boolean needs_more = FALSE;
2640         filedets = (lives_file_dets_t *)(list->data);
2641 
2642         if (!pass) {
2643           ccount++;
2644           lives_layout_add_row(LIVES_LAYOUT(renamew->clips_layout));
2645           if (!filedets->mtime_sec) dtxt = txt = lives_strdup("????");
2646           else {
2647             txt = lives_datetime(filedets->mtime_sec, TRUE);
2648             dtxt = lives_datetime_rel(txt);
2649           }
2650           filedets->widgets[0] = lives_layout_add_label(LIVES_LAYOUT(renamew->clips_layout), dtxt, TRUE);
2651           if (dtxt != txt) lives_free(dtxt);
2652           lives_free(txt);
2653         }
2654 
2655         if (!pass) {
2656           LiVESWidget *hbox = lives_layout_hbox_new(LIVES_LAYOUT(renamew->clips_layout));
2657           filedets->widgets[1] = lives_standard_label_new(NULL);
2658           lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[1]);
2659           if (filedets->size == -1) {
2660             lives_widget_hide(filedets->widgets[1]);
2661             lives_widget_set_no_show_all(filedets->widgets[1], TRUE);
2662             filedets->widgets[2] = lives_spinner_new();
2663             if (filedets->widgets[2]) {
2664               lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[2]);
2665               lives_spinner_start(LIVES_SPINNER(filedets->widgets[2]));
2666             } else filedets->widgets[2] = filedets->widgets[1];
2667           } else filedets->widgets[2] = filedets->widgets[1];
2668         }
2669 
2670         if (filedets->size == -1) {
2671           needs_more = TRUE;
2672         }
2673 
2674         if (filedets->size != -1) {
2675           if (filedets->mtime_sec) {
2676             txt = lives_datetime(filedets->mtime_sec, TRUE);
2677             dtxt = lives_datetime_rel(txt);
2678             lives_label_set_text(LIVES_LABEL(filedets->widgets[0]), dtxt);
2679             if (dtxt != txt) lives_free(dtxt);
2680             lives_free(txt);
2681           }
2682           if (filedets->widgets[2]) {
2683             if (filedets->widgets[2] != filedets->widgets[1]) {
2684               // remove spinner
2685               lives_spinner_stop(LIVES_SPINNER(filedets->widgets[2]));
2686               lives_widget_destroy(filedets->widgets[2]);
2687             }
2688             if (filedets->size == -2) {
2689               lives_label_set_text(LIVES_LABEL(filedets->widgets[1]), "????");
2690             }
2691             if (filedets->size > 0) {
2692               txt = lives_format_storage_space_string(filedets->size);
2693               lives_label_set_text(LIVES_LABEL(filedets->widgets[1]), txt);
2694               lives_free(txt);
2695             }
2696             lives_widget_set_no_show_all(filedets->widgets[1], FALSE);
2697             lives_widget_show(filedets->widgets[1]);
2698             filedets->widgets[2] = NULL;
2699           }
2700         }
2701 
2702         if (!pass) {
2703           LiVESWidget *hbox = lives_layout_hbox_new(LIVES_LAYOUT(renamew->clips_layout));
2704           filedets->widgets[3] = lives_standard_label_new(NULL);
2705           lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[3]);
2706           if (!filedets->extra_details) {
2707             lives_widget_hide(filedets->widgets[3]);
2708             lives_widget_set_no_show_all(filedets->widgets[3], TRUE);
2709             filedets->widgets[4] = lives_spinner_new();
2710             if (filedets->widgets[4]) {
2711               lives_layout_pack(LIVES_BOX(hbox), filedets->widgets[4]);
2712               lives_spinner_start(LIVES_SPINNER(filedets->widgets[4]));
2713             } else filedets->widgets[4] = filedets->widgets[3];
2714           } else filedets->widgets[4] = filedets->widgets[3];
2715         }
2716 
2717         if (!filedets->extra_details) {
2718           needs_more = TRUE;
2719         }
2720 
2721         if (filedets->extra_details) {
2722           if (filedets->widgets[4]) {
2723             if (filedets->widgets[4] != filedets->widgets[3]) {
2724               // remove spinner
2725               lives_spinner_stop(LIVES_SPINNER(filedets->widgets[4]));
2726               lives_widget_destroy(filedets->widgets[4]);
2727             }
2728             lives_label_set_text(LIVES_LABEL(filedets->widgets[3]), filedets->extra_details);
2729             lives_widget_set_no_show_all(filedets->widgets[3], FALSE);
2730             lives_widget_show(filedets->widgets[3]);
2731             if (LIVES_FILE_IS_MISSING(filedets->type))
2732               show_warn_image(filedets->widgets[3], NULL);
2733             filedets->widgets[4] = NULL;
2734           }
2735         }
2736         lives_widget_show_all(renamew->clips_layout);
2737 
2738         do {
2739           lives_widget_process_updates(renamew->dialog);
2740           if (lives_expander_get_expanded(LIVES_EXPANDER(exp)) && !pass && !list->next) lives_nanosleep(1000);
2741           if (totsize == -1) {
2742             if (lives_proc_thread_check(sizinfo)) {
2743               totsize = lives_proc_thread_join_int64(sizinfo);
2744               txt = mkszlabel(set, totsize, ccount, lcount);
2745               lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2746               lives_free(txt);
2747               lives_widget_process_updates(renamew->dialog);
2748             }
2749           }
2750         } while (!pass && !list->next && lives_expander_get_expanded(LIVES_EXPANDER(exp)));
2751 
2752         if (!lives_expander_get_expanded(LIVES_EXPANDER(exp))) goto thrdjoin;
2753         list = list->next;
2754         if (!list->data && needs_more) {
2755           list = *clipslist;
2756           pass++;
2757         }
2758       }
2759     }
2760     while (lives_expander_get_expanded(LIVES_EXPANDER(exp)) && totsize == -1) {
2761       if (lives_proc_thread_check(sizinfo)) {
2762         totsize = lives_proc_thread_join_int64(sizinfo);
2763       }
2764       if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) lives_widget_process_updates(renamew->dialog);
2765       if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) lives_nanosleep(1000);
2766     }
2767     txt = mkszlabel(set, totsize, ccount, lcount);
2768     lives_label_set_text(LIVES_LABEL(renamew->exp_label), txt);
2769     lives_free(txt);
2770     if (lives_expander_get_expanded(LIVES_EXPANDER(exp))) lives_widget_process_updates(renamew->dialog);
2771   }
2772 
2773 thrdjoin:
2774   lives_proc_thread_cancel(layinfo);
2775   lives_proc_thread_cancel(clipsinfo);
2776   lives_proc_thread_dontcare(sizinfo);
2777   if (*laylist) free_fdets_list(laylist);
2778   if (*clipslist) free_fdets_list(clipslist);
2779 }
2780 
2781 
close_expander(LiVESWidget * button,_entryw * renamew)2782 static void close_expander(LiVESWidget * button, _entryw * renamew) {
2783   if (lives_expander_get_expanded(LIVES_EXPANDER(renamew->expander)))
2784     lives_expander_set_expanded(LIVES_EXPANDER(renamew->expander), FALSE);
2785 }
2786 
renamew_entry_changed(LiVESEntry * entry,LiVESWidget * other)2787 static void renamew_entry_changed(LiVESEntry * entry, LiVESWidget * other) {
2788   if (!*(lives_entry_get_text(entry))) lives_widget_set_sensitive(other, FALSE);
2789   else lives_widget_set_sensitive(other, TRUE);
2790 }
2791 
create_rename_dialog(int type)2792 _entryw *create_rename_dialog(int type) {
2793   // type 1 = rename clip in menu
2794   // type 2 = save clip set
2795   // type 3 = reload clip set
2796   // type 4 = save clip set from mt
2797   // type 5 = save clip set for project export
2798 
2799   // type 6 = initial workdir / change workdir
2800 
2801   // type 7 = rename track in mt
2802 
2803   // type 8 = export theme
2804 
2805   LiVESWidget *dialog_vbox;
2806   LiVESWidget *hbox;
2807   LiVESWidget *label;
2808   LiVESWidget *checkbutton;
2809   LiVESWidget *set_combo;
2810 
2811   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
2812 
2813   char *title = NULL, *workdir, *tmp, *tmp2;
2814 
2815   _entryw *renamew = (_entryw *)(lives_calloc(1, sizeof(_entryw)));
2816 
2817   if (type == 1) {
2818     title = (_("Rename Clip"));
2819   } else if (type == 2 || type == 4 || type == 5) {
2820     title = (_("Enter Set Name to Save as"));
2821   } else if (type == 3) {
2822     title = (_("Enter a Set Name to Reload"));
2823   } else if (type == 6) {
2824     title = (_("Choose a Working Directory"));
2825   } else if (type == 7) {
2826     title = (_("Rename Current Track"));
2827   } else if (type == 8) {
2828     title = (_("Enter a Name for Your Theme"));
2829   }
2830 
2831   renamew->dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
2832   lives_free(title);
2833 
2834   lives_signal_handlers_disconnect_by_func(renamew->dialog, LIVES_GUI_CALLBACK(return_true), NULL);
2835 
2836   lives_window_add_accel_group(LIVES_WINDOW(renamew->dialog), accel_group);
2837 
2838   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(renamew->dialog));
2839 
2840   if (type == 4) {
2841     label = lives_standard_label_new
2842             (_("You need to enter a name for the current clip set.\n"
2843                "This will allow you reload the layout with the same clips later.\n"
2844                "Please enter the set name you wish to use.\n"
2845                "LiVES will remind you to save the clip set later when you try to exit.\n"));
2846     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, 0);
2847   }
2848 
2849   if (type == 5) {
2850     label = lives_standard_label_new
2851             (_("In order to export this project, you must enter a name for this clip set.\n"
2852                "This will also be used for the project name.\n"));
2853     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, 0);
2854   }
2855 
2856   if (type == 6 && !mainw->is_ready) {
2857     tmp = lives_big_and_bold(_("Welcome to LiVES !"));
2858     widget_opts.justify = LIVES_JUSTIFY_CENTER;
2859     widget_opts.use_markup = TRUE;
2860     label = lives_standard_label_new(tmp);
2861     widget_opts.use_markup = FALSE;
2862     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2863     lives_free(tmp);
2864     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
2865 
2866     label = lives_standard_label_new
2867             (_("This startup wizard will guide you through the\n"
2868                "initial install so that you can get the most from this application."));
2869     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
2870 
2871     label = lives_standard_label_new
2872             (_("First of all you need to choose a working directory for LiVES.\n"
2873                "This should be a directory with plenty of disk space available."));
2874     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
2875   }
2876 
2877   if (type == 6 && mainw->is_ready) {
2878     label = lives_standard_label_new(_("If the value of the working directory is changed, the contents of the existing\n"
2879                                        "working directory will be moved and if applicable added to the new location\n"));
2880     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
2881   }
2882 
2883   hbox = lives_hbox_new(FALSE, 0);
2884 
2885   if (type == 3) {
2886     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height * 4);
2887   } else if (type == 2 || type == 4 || type == 5) {
2888     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 2);
2889   } else {
2890     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 4);
2891   }
2892 
2893   if (type == 1 || type == 7) {
2894     label = lives_standard_label_new(_("New name "));
2895   } else if (type == 2 || type == 3 || type == 4 || type == 5) {
2896     label = lives_standard_label_new(_("Set name "));
2897   } else if (type == 8) {
2898     label = lives_standard_label_new(_("Theme name "));
2899   } else {
2900     label = lives_standard_label_new("");
2901   }
2902 
2903   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width * 4);
2904 
2905   if (type == 3) {
2906     if (mainw->num_sets == -1) {
2907       mainw->set_list = get_set_list(prefs->workdir, TRUE);
2908       if (mainw->set_list) {
2909         mainw->num_sets = lives_list_length(mainw->set_list);
2910         if (mainw->was_set) mainw->num_sets--;
2911       } else mainw->num_sets = 0;
2912       if (!mainw->num_sets) {
2913         do_no_sets_dialog(prefs->workdir);
2914         return NULL;
2915       }
2916     }
2917     mainw->set_list = lives_list_sort_alpha(mainw->set_list, TRUE);
2918     set_combo = lives_standard_combo_new(NULL, mainw->set_list, LIVES_BOX(hbox), NULL);
2919     renamew->entry = lives_combo_get_entry(LIVES_COMBO(set_combo));
2920     lives_entry_set_editable(LIVES_ENTRY(renamew->entry), TRUE);
2921     lives_entry_set_max_length(LIVES_ENTRY(renamew->entry), MAX_SET_NAME_LEN);
2922 
2923     if (*prefs->ar_clipset_name) {
2924       // set default to our auto-reload clipset
2925       lives_entry_set_text(LIVES_ENTRY(renamew->entry), prefs->ar_clipset_name);
2926     }
2927     lives_entry_set_completion_from_list(LIVES_ENTRY(renamew->entry), mainw->set_list);
2928   } else {
2929     if (type == 6) {
2930       LiVESWidget *dirbutton;
2931       if (*prefs->workdir) workdir = lives_strdup(prefs->workdir);
2932       else workdir = lives_build_path(capable->home_dir, LIVES_DEF_WORK_NAME, NULL);
2933       renamew->entry = lives_standard_direntry_new("", (tmp = F2U8(workdir)),
2934                        LONG_ENTRY_WIDTH, PATH_MAX, LIVES_BOX(hbox),
2935                        (tmp2 = (_("LiVES working directory."))));
2936 
2937       dirbutton = lives_label_get_mnemonic_widget(LIVES_LABEL(widget_opts.last_label));
2938       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(dirbutton), FILESEL_TYPE_KEY,
2939                                    LIVES_INT_TO_POINTER(LIVES_DIR_SELECTION_WORKDIR));
2940 
2941       lives_free(tmp);
2942       lives_free(workdir);
2943     } else {
2944       renamew->entry = lives_standard_entry_new(NULL, NULL, -1, -1, LIVES_BOX(hbox), NULL);
2945       lives_entry_set_max_length(LIVES_ENTRY(renamew->entry), type == 6 ? PATH_MAX
2946                                  : type == 7 ? 16 : 128);
2947       if (type == 2 && *mainw->set_name) {
2948         lives_entry_set_text(LIVES_ENTRY(renamew->entry), (tmp = F2U8(mainw->set_name)));
2949         lives_free(tmp);
2950       }
2951     }
2952   }
2953 
2954   add_fill_to_box(LIVES_BOX(dialog_vbox));
2955 
2956   if (type == 3) {
2957     /// add set details expander
2958     int winsize_h = RFX_WINSIZE_H * 2;
2959     int winsize_v = RFX_WINSIZE_V / 2;
2960     LiVESWidget *layout;
2961     LiVESWidget *scrolledwindow;
2962     LiVESWidget *vbox = lives_vbox_new(FALSE, 0);
2963     int woat = widget_opts.apply_theme;
2964 
2965     layout = lives_layout_new(LIVES_BOX(vbox));
2966     lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
2967     renamew->exp_label = lives_layout_add_label(LIVES_LAYOUT(layout), "", FALSE);
2968     lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
2969 
2970     renamew->exp_vbox = lives_vbox_new(FALSE, 0);
2971     widget_opts.apply_theme = 0;
2972     scrolledwindow = lives_standard_scrolled_window_new(winsize_h, winsize_v, renamew->exp_vbox);
2973     widget_opts.apply_theme = woat;
2974     lives_box_pack_start(LIVES_BOX(vbox), scrolledwindow, TRUE, TRUE, widget_opts.packing_height);
2975     widget_opts.justify = LIVES_JUSTIFY_CENTER;
2976     renamew->expander = lives_standard_expander_new(NULL, LIVES_BOX(dialog_vbox), vbox);
2977     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
2978     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(renamew->expander), LIVES_WIDGET_ACTIVATE_SIGNAL,
2979                                     LIVES_GUI_CALLBACK(on_set_exp), renamew);
2980     on_set_exp(renamew->expander, renamew);
2981     add_fill_to_box(LIVES_BOX(dialog_vbox));
2982     add_fill_to_box(LIVES_BOX(dialog_vbox));
2983     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(renamew->entry), LIVES_WIDGET_CHANGED_SIGNAL,
2984                                     LIVES_GUI_CALLBACK(renamew_entry_changed), renamew->expander);
2985     renamew_entry_changed(LIVES_ENTRY(renamew->entry), renamew->expander);
2986   }
2987 
2988   if (type == 8) {
2989     mainw->fx1_bool = FALSE;
2990     hbox = lives_hbox_new(FALSE, 0);
2991     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 4);
2992 
2993     checkbutton = lives_standard_check_button_new(_("Save extended colors"), FALSE, LIVES_BOX(hbox), NULL);
2994 
2995     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2996                                     LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->fx1_bool);
2997   }
2998 
2999   lives_entry_set_width_chars(LIVES_ENTRY(renamew->entry), MEDIUM_ENTRY_WIDTH);
3000 
3001   if (!(type == 4 && !LIVES_IS_INTERACTIVE)) {
3002     renamew->cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(renamew->dialog), LIVES_STOCK_CANCEL, NULL,
3003                             LIVES_RESPONSE_CANCEL);
3004     lives_widget_add_accelerator(renamew->cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
3005                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
3006   }
3007 
3008   if (type == 6 && !mainw->is_ready) {
3009     renamew->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(renamew->dialog), LIVES_STOCK_GO_FORWARD, _("_Next"),
3010                         LIVES_RESPONSE_OK);
3011   } else renamew->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(renamew->dialog), LIVES_STOCK_OK,
3012                                NULL, LIVES_RESPONSE_OK);
3013 
3014   lives_button_grab_default_special(renamew->okbutton);
3015 
3016   if (type != 3 && renamew->cancelbutton) {
3017     lives_signal_sync_connect(LIVES_GUI_OBJECT(renamew->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3018                               LIVES_GUI_CALLBACK(lives_general_button_clicked), renamew);
3019   }
3020 
3021   if (type == 3) {
3022     if (renamew->cancelbutton) {
3023       lives_signal_sync_connect(LIVES_GUI_OBJECT(renamew->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3024                                 LIVES_GUI_CALLBACK(close_expander), renamew);
3025     }
3026     if (renamew->okbutton) {
3027       lives_signal_sync_connect(LIVES_GUI_OBJECT(renamew->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3028                                 LIVES_GUI_CALLBACK(close_expander), renamew);
3029     }
3030   }
3031 
3032   if (type == 1) {
3033     lives_signal_sync_connect(LIVES_GUI_OBJECT(renamew->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3034                               LIVES_GUI_CALLBACK(on_rename_clip_name), NULL);
3035   }
3036 
3037   lives_widget_add_accelerator(renamew->cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
3038                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
3039 
3040   lives_widget_show_all(renamew->dialog);
3041   lives_widget_grab_focus(renamew->entry);
3042 
3043   return renamew;
3044 }
3045 
3046 
on_liveinp_advanced_clicked(LiVESButton * button,livespointer user_data)3047 void on_liveinp_advanced_clicked(LiVESButton * button, livespointer user_data) {
3048   lives_tvcardw_t *tvcardw = (lives_tvcardw_t *)(user_data);
3049 
3050   tvcardw->use_advanced = !tvcardw->use_advanced;
3051 
3052   if (tvcardw->use_advanced) {
3053     lives_widget_show(tvcardw->adv_vbox);
3054     lives_button_set_label(LIVES_BUTTON(tvcardw->advbutton), _("Use def_aults"));
3055   } else {
3056     lives_button_set_label(LIVES_BUTTON(tvcardw->advbutton), _("_Advanced"));
3057     lives_window_resize(LIVES_WINDOW(lives_widget_get_toplevel(tvcardw->adv_vbox)), 4, 40);
3058     lives_widget_hide(tvcardw->adv_vbox);
3059   }
3060 
3061   lives_widget_queue_resize(lives_widget_get_parent(tvcardw->adv_vbox));
3062 }
3063 
3064 
rb_tvcarddef_toggled(LiVESToggleButton * tbut,livespointer user_data)3065 static void rb_tvcarddef_toggled(LiVESToggleButton * tbut, livespointer user_data) {
3066   lives_tvcardw_t *tvcardw = (lives_tvcardw_t *)(user_data);
3067 
3068   if (!lives_toggle_button_get_active(tbut)) {
3069     lives_widget_set_sensitive(tvcardw->spinbuttonw, TRUE);
3070     lives_widget_set_sensitive(tvcardw->spinbuttonh, TRUE);
3071     lives_widget_set_sensitive(tvcardw->spinbuttonf, TRUE);
3072   } else {
3073     lives_widget_set_sensitive(tvcardw->spinbuttonw, FALSE);
3074     lives_widget_set_sensitive(tvcardw->spinbuttonh, FALSE);
3075     lives_widget_set_sensitive(tvcardw->spinbuttonf, FALSE);
3076   }
3077 }
3078 
3079 
after_dialog_combo_changed(LiVESWidget * combo,livespointer plist)3080 static void after_dialog_combo_changed(LiVESWidget * combo, livespointer plist) {
3081   // set mainw->fx1_val to the index of combo text in plist
3082   LiVESList *list = (LiVESList *)plist;
3083   const char *etext = lives_combo_get_active_text(LIVES_COMBO(combo));
3084   mainw->fx1_val = lives_list_strcmp_index(list, etext, TRUE);
3085 }
3086 
3087 
create_combo_dialog(int type,LiVESList * list)3088 LiVESWidget *create_combo_dialog(int type, LiVESList * list) {
3089   // create a dialog with combo box selector
3090 
3091   // type 1 == unicap device
3092 
3093   // afterwards, mainw->fx1_val points to index selected
3094 
3095   LiVESWidget *combo_dialog;
3096   LiVESWidget *dialog_vbox;
3097   LiVESWidget *label;
3098   LiVESWidget *combo;
3099 
3100   char *label_text = NULL, *title = NULL;
3101 
3102   if (type == 1) {
3103     title = (_("Select input device"));
3104   }
3105 
3106   combo_dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
3107   if (title) lives_free(title);
3108 
3109   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(combo_dialog));
3110 
3111   if (type == 1) {
3112     label_text = (_("Select input device:"));
3113   }
3114 
3115   label = lives_standard_label_new(label_text);
3116   if (label_text) lives_free(label_text);
3117 
3118   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, TRUE, TRUE, 0);
3119 
3120   widget_opts.packing_height <<= 1;
3121   combo = lives_standard_combo_new(NULL, list, LIVES_BOX(dialog_vbox), NULL);
3122   widget_opts.packing_height >>= 1;
3123 
3124   lives_signal_sync_connect_after(LIVES_WIDGET_OBJECT(combo), LIVES_WIDGET_CHANGED_SIGNAL,
3125                                   LIVES_GUI_CALLBACK(after_dialog_combo_changed), list);
3126 
3127   if (type == 1) {
3128     add_deinterlace_checkbox(LIVES_BOX(dialog_vbox));
3129   }
3130 
3131   if (prefs->show_gui)
3132     lives_widget_show_all(combo_dialog);
3133 
3134   return combo_dialog;
3135 }
3136 
3137 
create_cdtrack_dialog(int type,livespointer user_data)3138 LiVESWidget *create_cdtrack_dialog(int type, livespointer user_data) {
3139   // general purpose device dialog with label and up to 2 spinbuttons
3140 
3141   // type 0 = cd track
3142   // type 1 = dvd title/chapter/aid
3143   // type 2 = vcd title -- do we need chapter as well ?
3144 
3145   // type 3 = number of tracks in mt
3146 
3147   // type 4 = TV card (device and channel)
3148   // type 5 = fw card
3149 
3150   // TODO - for CD make this nicer - get track names
3151 
3152   lives_tvcardw_t *tvcardw = NULL;
3153 
3154   LiVESWidget *cd_dialog;
3155   LiVESWidget *dialog_vbox;
3156   LiVESWidget *hbox;
3157   LiVESWidget *spinbutton;
3158   LiVESWidget *cancelbutton;
3159   LiVESWidget *okbutton;
3160 
3161   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
3162 
3163   LiVESSList *radiobutton_group = NULL;
3164 
3165   char *label_text = NULL, *title;
3166 
3167   int ph_mult = 4;
3168 
3169   if (type == LIVES_DEVICE_CD) {
3170     title = (_("Load CD Track"));
3171   } else if (type == LIVES_DEVICE_DVD) {
3172     title = (_("Select DVD Title/Chapter"));
3173   } else if (type == LIVES_DEVICE_VCD) {
3174     title = (_("Select VCD Title"));
3175   } else if (type == LIVES_DEVICE_INTERNAL) {
3176     title = (_("Change Maximum Visible Tracks"));
3177   } else {
3178     title = (_("Device details"));
3179   }
3180 
3181   cd_dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
3182   lives_free(title);
3183   lives_signal_handlers_disconnect_by_func(cd_dialog, LIVES_GUI_CALLBACK(return_true), NULL);
3184 
3185   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(cd_dialog));
3186 
3187   if (type == LIVES_DEVICE_DVD || type == LIVES_DEVICE_TV_CARD) ph_mult = 2;
3188 
3189   hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3190   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * ph_mult);
3191 
3192   if (type == LIVES_DEVICE_CD) {
3193     label_text = lives_strdup_printf(_("Track to load (from %s)"), prefs->cdplay_device);
3194   } else if (type == LIVES_DEVICE_DVD) {
3195     label_text = (_("DVD Title"));
3196   } else if (type == LIVES_DEVICE_VCD) {
3197     label_text = (_("VCD Title"));
3198   } else if (type == LIVES_DEVICE_INTERNAL) {
3199     label_text = (_("Maximum number of tracks to display"));
3200   } else if (type == LIVES_DEVICE_TV_CARD) {
3201     label_text = (_("Device:        /dev/video"));
3202   } else if (type == LIVES_DEVICE_FW_CARD) {
3203     label_text = (_("Device:        fw:"));
3204   }
3205 
3206   widget_opts.mnemonic_label = FALSE;
3207   if (type == LIVES_DEVICE_CD || type == LIVES_DEVICE_DVD || type == LIVES_DEVICE_VCD) {
3208     spinbutton = lives_standard_spin_button_new(label_text, mainw->fx1_val,
3209                  1., 256., 1., 10., 0, LIVES_BOX(hbox), NULL);
3210   } else if (type == LIVES_DEVICE_INTERNAL) {
3211     spinbutton = lives_standard_spin_button_new(label_text, mainw->fx1_val,
3212                  5., 15., 1., 1., 0, LIVES_BOX(hbox), NULL);
3213   } else {
3214     spinbutton = lives_standard_spin_button_new(label_text, 0.,
3215                  0., 31., 1., 1., 0, LIVES_BOX(hbox), NULL);
3216   }
3217   widget_opts.mnemonic_label = TRUE;
3218 
3219   lives_free(label_text);
3220 
3221   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3222                                   LIVES_GUI_CALLBACK(on_spin_value_changed),
3223                                   LIVES_INT_TO_POINTER(1));
3224 
3225   add_fill_to_box(LIVES_BOX(hbox));
3226 
3227   if (type == LIVES_DEVICE_DVD || type == LIVES_DEVICE_TV_CARD) {
3228     hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3229     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * ph_mult);
3230 
3231     if (type == LIVES_DEVICE_DVD) {
3232       spinbutton = lives_standard_spin_button_new(_("Chapter  "), mainw->fx2_val,
3233                    1., 1024., 1., 10., 0, LIVES_BOX(hbox), NULL);
3234     } else {
3235       spinbutton = lives_standard_spin_button_new(_("Channel  "), 1.,
3236                    1., 69., 1., 1., 0, LIVES_BOX(hbox), NULL);
3237     }
3238 
3239     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3240                                     LIVES_GUI_CALLBACK(on_spin_value_changed), LIVES_INT_TO_POINTER(2));
3241 
3242     if (type == LIVES_DEVICE_DVD) {
3243       hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3244       lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * ph_mult);
3245 
3246       spinbutton = lives_standard_spin_button_new(_("Audio ID  "), mainw->fx3_val,
3247                    DVD_AUDIO_CHAN_MIN, DVD_AUDIO_CHAN_MAX, 1., 1., 0, LIVES_BOX(hbox), NULL);
3248 
3249       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3250                                       LIVES_GUI_CALLBACK(on_spin_value_changed),
3251                                       LIVES_INT_TO_POINTER(3));
3252     }
3253   }
3254 
3255   if (type == LIVES_DEVICE_TV_CARD || type == LIVES_DEVICE_FW_CARD) {
3256     hbox = add_deinterlace_checkbox(LIVES_BOX(dialog_vbox));
3257     add_fill_to_box(LIVES_BOX(hbox));
3258   }
3259 
3260   if (type == LIVES_DEVICE_TV_CARD) {
3261     LiVESList *dlist = NULL;
3262     LiVESList *olist = NULL;
3263     char const *str;
3264     char *tvcardtypes[] = LIVES_TV_CARD_TYPES;
3265     register int i;
3266 
3267     tvcardw = (lives_tvcardw_t *)lives_malloc(sizeof(lives_tvcardw_t));
3268     tvcardw->use_advanced = FALSE;
3269 
3270     for (i = 0; (str = tvcardtypes[i]); i++) {
3271       dlist = lives_list_append(dlist, (livespointer)tvcardtypes[i]);
3272     }
3273 
3274     lives_box_set_spacing(LIVES_BOX(dialog_vbox), widget_opts.packing_height * 2);
3275 
3276     hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3277 
3278     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height * 2);
3279 
3280     add_fill_to_box(LIVES_BOX(hbox));
3281 
3282     tvcardw->advbutton = lives_standard_button_new_from_stock(LIVES_STOCK_PREFERENCES, _("_Advanced"),
3283                          DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
3284 
3285     lives_box_pack_start(LIVES_BOX(hbox), tvcardw->advbutton, TRUE, TRUE, widget_opts.packing_width * 4);
3286 
3287     add_fill_to_box(LIVES_BOX(hbox));
3288 
3289     tvcardw->adv_vbox = lives_vbox_new(FALSE, widget_opts.packing_width * 5);
3290     lives_box_pack_start(LIVES_BOX(dialog_vbox), tvcardw->adv_vbox, TRUE, TRUE, widget_opts.packing_height * 2);
3291 
3292     // add input, width, height, fps, driver and outfmt
3293 
3294     hbox = lives_hbox_new(FALSE, 0);
3295     lives_box_pack_start(LIVES_BOX(tvcardw->adv_vbox), hbox, TRUE, FALSE, 0);
3296 
3297     tvcardw->spinbuttoni = lives_standard_spin_button_new(_("Input number"),
3298                            0., 0., 16., 1., 1., 0, LIVES_BOX(hbox), NULL);
3299 
3300     hbox = lives_hbox_new(FALSE, 0);
3301     lives_box_pack_start(LIVES_BOX(tvcardw->adv_vbox), hbox, TRUE, FALSE, 0);
3302 
3303     tvcardw->radiobuttond = lives_standard_radio_button_new(_("Use default width, height and FPS"),
3304                             &radiobutton_group, LIVES_BOX(hbox), NULL);
3305 
3306     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tvcardw->radiobuttond), LIVES_WIDGET_TOGGLED_SIGNAL,
3307                                     LIVES_GUI_CALLBACK(rb_tvcarddef_toggled), (livespointer)tvcardw);
3308 
3309     hbox = lives_hbox_new(FALSE, 0);
3310     lives_box_pack_start(LIVES_BOX(tvcardw->adv_vbox), hbox, TRUE, FALSE, 0);
3311 
3312     lives_standard_radio_button_new(NULL, &radiobutton_group, LIVES_BOX(hbox), NULL);
3313 
3314     tvcardw->spinbuttonw = lives_standard_spin_button_new(_("Width"),
3315                            640., 4., 4096., 4., 16., 0, LIVES_BOX(hbox), NULL);
3316 
3317     lives_widget_set_sensitive(tvcardw->spinbuttonw, FALSE);
3318 
3319     tvcardw->spinbuttonh = lives_standard_spin_button_new(_("Height"),
3320                            480., 4., 4096., 4., 16., 0, LIVES_BOX(hbox), NULL);
3321 
3322     lives_widget_set_sensitive(tvcardw->spinbuttonh, FALSE);
3323 
3324     tvcardw->spinbuttonf = lives_standard_spin_button_new(_("FPS"),
3325                            25., 1., FPS_MAX, 1., 10., 3, LIVES_BOX(hbox), NULL);
3326 
3327     lives_widget_set_sensitive(tvcardw->spinbuttonf, FALSE);
3328 
3329     hbox = lives_hbox_new(FALSE, 0);
3330 
3331     tvcardw->combod = lives_standard_combo_new(_("_Driver"), dlist, LIVES_BOX(hbox), NULL);
3332     lives_combo_set_active_index(LIVES_COMBO(tvcardw->combod), 0);
3333 
3334     tvcardw->comboo = lives_standard_combo_new(_("_Output format"), olist, LIVES_BOX(hbox), NULL);
3335 
3336     lives_widget_show_all(hbox);
3337     lives_box_pack_start(LIVES_BOX(tvcardw->adv_vbox), hbox, TRUE, FALSE, 0);
3338 
3339     lives_signal_sync_connect(LIVES_GUI_OBJECT(tvcardw->advbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3340                               LIVES_GUI_CALLBACK(on_liveinp_advanced_clicked), tvcardw);
3341 
3342     lives_widget_hide(tvcardw->adv_vbox);
3343 
3344     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cd_dialog), "tvcard_data", tvcardw);
3345   }
3346 
3347   add_fill_to_box(LIVES_BOX(dialog_vbox));
3348 
3349   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(cd_dialog), LIVES_STOCK_CANCEL, NULL,
3350                  LIVES_RESPONSE_CANCEL);
3351   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(cd_dialog), LIVES_STOCK_OK, NULL,
3352              LIVES_RESPONSE_OK);
3353   lives_button_grab_default_special(okbutton);
3354 
3355   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
3356                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
3357 
3358   if (type != LIVES_DEVICE_TV_CARD && type != LIVES_DEVICE_FW_CARD) {
3359     lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3360                               LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
3361   }
3362 
3363   if (type == LIVES_DEVICE_CD) {
3364     lives_signal_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3365                          LIVES_GUI_CALLBACK(on_load_cdtrack_ok_clicked), NULL);
3366   } else if (type == LIVES_DEVICE_DVD || type == LIVES_DEVICE_VCD)  {
3367     lives_signal_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3368                          LIVES_GUI_CALLBACK(on_load_vcd_ok_clicked), LIVES_INT_TO_POINTER(type));
3369   } else if (type == LIVES_DEVICE_INTERNAL)  {
3370     lives_signal_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3371                          LIVES_GUI_CALLBACK(mt_change_disp_tracks_ok), user_data);
3372   }
3373 
3374   lives_window_add_accel_group(LIVES_WINDOW(cd_dialog), accel_group);
3375 
3376   lives_widget_show_all(cd_dialog);
3377 
3378   if (type == LIVES_DEVICE_TV_CARD) lives_widget_hide(tvcardw->adv_vbox);
3379 
3380   return cd_dialog;
3381 }
3382 
3383 
on_avolch_ok(LiVESButton * button,livespointer data)3384 static void on_avolch_ok(LiVESButton * button, livespointer data) {
3385   if (fabs(cfile->vol - mainw->fx1_val) > .005) {
3386     uint32_t chk_mask = WARN_MASK_LAYOUT_ALTER_AUDIO;
3387     char *tmp = (_("Changing the audio volume"));
3388     lives_general_button_clicked(button, NULL);
3389     if (check_for_layout_errors(tmp, mainw->current_file, 1,
3390                                 calc_frame_from_time4(mainw->current_file, CLIP_AUDIO_TIME(mainw->current_file)), &chk_mask)) {
3391       d_print(_("Adjusting clip volume..."));
3392       lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
3393       if (!adjust_clip_volume(mainw->current_file, lives_vol_from_linear(mainw->fx1_val), !prefs->conserve_space)) {
3394         d_print_failed();
3395         unbuffer_lmap_errors(FALSE);
3396         lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
3397         return;
3398       }
3399       set_undoable(_("Volume Adjustment"), TRUE);
3400       cfile->undo_action = UNDO_AUDIO_VOL;
3401       update_timer_bars(0, 0, 0, 0, 2);
3402       update_timer_bars(0, 0, 0, 0, 3);
3403       d_print(_("clip volume adjusted by a factor of %.2f\n"), cfile->vol);
3404       cfile->vol = 1.;
3405     } else d_print_cancelled();
3406     lives_free(tmp);
3407     lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
3408   }
3409 }
3410 
3411 
redraw_timeline(int clipno)3412 void redraw_timeline(int clipno) {
3413   lives_clip_t *sfile;
3414 
3415   if (mainw->ce_thumbs) return;
3416   if (!IS_VALID_CLIP(clipno)) return;
3417   sfile = mainw->files[clipno];
3418   if (sfile->clip_type == CLIP_TYPE_TEMP) return;
3419 
3420   mainw->drawsrc = clipno;
3421 
3422   if (!mainw->video_drawable) {
3423     mainw->video_drawable = lives_widget_create_painter_surface(mainw->video_draw);
3424   }
3425   update_timer_bars(0, 0, 0, 0, 1);
3426 
3427   if (!sfile->laudio_drawable) {
3428     sfile->laudio_drawable = lives_widget_create_painter_surface(mainw->laudio_draw);
3429     mainw->laudio_drawable = sfile->laudio_drawable;
3430     clear_tbar_bgs(0, 0, 0, 0, 2);
3431     update_timer_bars(0, 0, 0, 0, 2);
3432   } else {
3433     mainw->laudio_drawable = sfile->laudio_drawable;
3434     if (!LIVES_IS_PLAYING) {
3435       update_timer_bars(0, 0, 0, 0, 2);
3436     }
3437   }
3438   if (!sfile->raudio_drawable) {
3439     sfile->raudio_drawable = lives_widget_create_painter_surface(mainw->raudio_draw);
3440     mainw->raudio_drawable = sfile->raudio_drawable;
3441     clear_tbar_bgs(0, 0, 0, 0, 3);
3442     update_timer_bars(0, 0, 0, 0, 3);
3443   } else {
3444     mainw->raudio_drawable = sfile->raudio_drawable;
3445     if (!LIVES_IS_PLAYING) {
3446       update_timer_bars(0, 0, 0, 0, 3);
3447     }
3448   }
3449 
3450   lives_widget_queue_draw(mainw->video_draw);
3451   lives_widget_queue_draw(mainw->laudio_draw);
3452   lives_widget_queue_draw(mainw->raudio_draw);
3453   lives_widget_queue_draw(mainw->eventbox2);
3454 }
3455 
3456 
redraw_tl_idle(void * data)3457 boolean redraw_tl_idle(void *data) {
3458   redraw_timeline(mainw->current_file);
3459   return FALSE;
3460 }
3461 
3462 //static void preview_aud_vol_cb(LiVESButton *button, livespointer data) {preview_aud_vol();}
3463 
create_new_pb_speed(short type)3464 void create_new_pb_speed(short type) {
3465   // type 1 = change speed
3466   // type 2 = resample
3467   // type 3 = clip audio volume
3468 
3469   LiVESWidget *new_pb_speed;
3470   LiVESWidget *dialog_vbox;
3471   LiVESWidget *vbox;
3472   LiVESWidget *hbox;
3473   LiVESWidget *ca_hbox;
3474   LiVESWidget *label;
3475   LiVESWidget *label2;
3476   LiVESWidget *radiobutton1 = NULL;
3477   LiVESWidget *radiobutton2 = NULL;
3478   LiVESWidget *spinbutton_pb_speed;
3479   LiVESWidget *spinbutton_pb_time = NULL;
3480   LiVESWidget *cancelbutton;
3481   LiVESWidget *change_pb_ok;
3482   LiVESWidget *change_audio_speed;
3483 
3484   LiVESAccelGroup *accel_group;
3485 
3486   LiVESSList *rbgroup = NULL;
3487 
3488   char label_text[256];
3489 
3490   char *title = NULL;
3491 
3492   if (type == 1) {
3493     title = (_("Change Playback Speed"));
3494   } else if (type == 2) {
3495     title = (_("Resample Video"));
3496   } else {
3497     title = (_("Adjust Clip Volume"));
3498   }
3499 
3500   new_pb_speed = lives_standard_dialog_new(title, FALSE, -1, -1);
3501   lives_signal_handlers_disconnect_by_func(new_pb_speed, LIVES_GUI_CALLBACK(return_true), NULL);
3502   lives_free(title);
3503 
3504   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
3505   lives_window_add_accel_group(LIVES_WINDOW(new_pb_speed), accel_group);
3506 
3507   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(new_pb_speed));
3508 
3509   vbox = lives_vbox_new(FALSE, widget_opts.packing_height * 2);
3510 
3511   lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox, TRUE, TRUE, 0);
3512 
3513   if (type == 1) {
3514     lives_snprintf(label_text, 256,
3515                    _("Current playback speed is %.3f frames per second.\n\n"
3516                      "Please enter the desired playback speed\nin _frames per second"),
3517                    cfile->fps);
3518   } else if (type == 2) {
3519     lives_snprintf(label_text, 256,
3520                    _("Current playback speed is %.3f frames per second.\n\n"
3521                      "Please enter the _resampled rate\nin frames per second"),
3522                    cfile->fps);
3523   } else if (type == 3) {
3524     lives_snprintf(label_text, 256,
3525                    _("Current volume level for this clip is %.2f.\n\n"
3526                      "You may select a new  _volume level here.\n\n"
3527                      "Please note that the volume can also be varied during playback\n"
3528                      "using the %s and %s keys.\nChanging it here will make "
3529                      "the adjustment permanent.\n"), "'<'", "'>'", cfile->vol);
3530   }
3531 
3532   label = lives_standard_label_new_with_mnemonic_widget(label_text, NULL);
3533 
3534   hbox = lives_hbox_new(FALSE, 0);
3535   lives_box_pack_start(LIVES_BOX(vbox), label, FALSE, FALSE, widget_opts.packing_height);
3536   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3537 
3538   if (type == 3) {
3539     add_fill_to_box(LIVES_BOX(hbox));
3540     spinbutton_pb_speed = lives_standard_spin_button_new(NULL, (double)cfile->vol, 0., 4., .01, .01, 2, LIVES_BOX(hbox), NULL);
3541     add_fill_to_box(LIVES_BOX(hbox));
3542   } else if (type == 2) {
3543     add_fill_to_box(LIVES_BOX(hbox));
3544     spinbutton_pb_speed = lives_standard_spin_button_new(NULL, cfile->fps, 1., FPS_MAX, .01, .1, 3, LIVES_BOX(hbox), NULL);
3545     add_fill_to_box(LIVES_BOX(hbox));
3546   } else {
3547     radiobutton1 = lives_standard_radio_button_new(NULL, &rbgroup, LIVES_BOX(hbox), NULL);
3548 
3549     spinbutton_pb_speed = lives_standard_spin_button_new(NULL, cfile->fps, 1., FPS_MAX, .01, .1, 3, LIVES_BOX(hbox), NULL);
3550 
3551     hbox = lives_hbox_new(FALSE, 0);
3552     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3553 
3554     add_fill_to_box(LIVES_BOX(hbox));
3555 
3556     label2 = lives_standard_label_new_with_mnemonic_widget(_("OR enter the desired clip length in _seconds"), NULL);
3557     lives_box_pack_start(LIVES_BOX(hbox), label2, TRUE, TRUE, widget_opts.packing_width);
3558 
3559     add_fill_to_box(LIVES_BOX(hbox));
3560 
3561     hbox = lives_hbox_new(FALSE, 0);
3562     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3563 
3564     radiobutton2 = lives_standard_radio_button_new(NULL, &rbgroup, LIVES_BOX(hbox), NULL);
3565 
3566     spinbutton_pb_time = lives_standard_spin_button_new(NULL,
3567                          (double)((int)(cfile->frames / cfile->fps * 100.)) / 100.,
3568                          1. / FPS_MAX, cfile->frames, 1., 10., 2, LIVES_BOX(hbox), NULL);
3569 
3570     lives_label_set_mnemonic_widget(LIVES_LABEL(label2), spinbutton_pb_time);
3571   }
3572 
3573   lives_label_set_mnemonic_widget(LIVES_LABEL(label), spinbutton_pb_speed);
3574 
3575   add_fill_to_box(LIVES_BOX(vbox));
3576 
3577   if (type < 3) {
3578     ca_hbox = lives_hbox_new(FALSE, 0);
3579     change_audio_speed = lives_standard_check_button_new
3580                          (_("Change the _audio speed as well"), FALSE, LIVES_BOX(ca_hbox), NULL);
3581 
3582     lives_box_pack_start(LIVES_BOX(vbox), ca_hbox, TRUE, TRUE, widget_opts.packing_height);
3583 
3584     add_fill_to_box(LIVES_BOX(vbox));
3585 
3586     if (type != 1 || cfile->achans == 0) lives_widget_set_no_show_all(ca_hbox, TRUE);
3587   }
3588 
3589   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(new_pb_speed), LIVES_STOCK_CANCEL, NULL,
3590                  LIVES_RESPONSE_CANCEL);
3591 
3592   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
3593                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
3594 
3595   /// TODO: needs more work to enable easy playback of audio without the video
3596   /* if (type == 3) { */
3597   /*   char *tmp; */
3598   /*   LiVESWidget *playbutt = lives_dialog_add_button_from_stock(LIVES_DIALOG(new_pb_speed), */
3599   /*                           LIVES_STOCK_MEDIA_PLAY, */
3600   /*                           (tmp = (cfile->real_pointer_time > 0. || (cfile->start == 1 && cfile->end == cfile->frames) ? */
3601   /*                                   (_("Preview audio")) : */
3602   /*                                   (_("Preview audio in selected range")))), */
3603   /*                           LIVES_RESPONSE_CANCEL); */
3604   /*   lives_free(tmp); */
3605   /*   lives_signal_connect(LIVES_GUI_OBJECT(playbutt), LIVES_WIDGET_CLICKED_SIGNAL, */
3606   /*                        LIVES_GUI_CALLBACK(preview_aud_vol_cb), */
3607   /*                        NULL); */
3608   /* } */
3609 
3610   change_pb_ok = lives_dialog_add_button_from_stock(LIVES_DIALOG(new_pb_speed), LIVES_STOCK_OK, NULL,
3611                  LIVES_RESPONSE_OK);
3612 
3613   lives_button_grab_default_special(change_pb_ok);
3614   lives_widget_grab_focus(spinbutton_pb_speed);
3615 
3616   if (type < 3) {
3617     reorder_leave_back_set(FALSE);
3618     lives_signal_sync_connect(LIVES_GUI_OBJECT(change_audio_speed), LIVES_WIDGET_TOGGLED_SIGNAL,
3619                               LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->fx1_bool);
3620   }
3621   lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
3622                             LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
3623   if (type == 1) {
3624     lives_signal_sync_connect(LIVES_GUI_OBJECT(change_pb_ok), LIVES_WIDGET_CLICKED_SIGNAL,
3625                               LIVES_GUI_CALLBACK(on_change_speed_ok_clicked), NULL);
3626   } else if (type == 2) {
3627     lives_signal_connect(LIVES_GUI_OBJECT(change_pb_ok), LIVES_WIDGET_CLICKED_SIGNAL,
3628                          LIVES_GUI_CALLBACK(on_resample_vid_ok), NULL);
3629 
3630   } else if (type == 3) {
3631     lives_signal_sync_connect(LIVES_GUI_OBJECT(change_pb_ok), LIVES_WIDGET_CLICKED_SIGNAL,
3632                               LIVES_GUI_CALLBACK(on_avolch_ok), NULL);
3633   }
3634 
3635   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_pb_speed), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3636                                   LIVES_GUI_CALLBACK(on_spin_value_changed), LIVES_INT_TO_POINTER(1));
3637 
3638   if (type == 1) {
3639     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_pb_time), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3640                                     LIVES_GUI_CALLBACK(on_spin_value_changed), LIVES_INT_TO_POINTER(2));
3641     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_pb_speed), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3642                                     LIVES_GUI_CALLBACK(widget_act_toggle), radiobutton1);
3643     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_pb_time), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
3644                                     LIVES_GUI_CALLBACK(widget_act_toggle), radiobutton2);
3645     lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton2), LIVES_WIDGET_TOGGLED_SIGNAL,
3646                               LIVES_GUI_CALLBACK(on_boolean_toggled), &mainw->fx2_bool);
3647   }
3648 
3649   lives_widget_show_all(new_pb_speed);
3650 }
3651 
3652 
rb_aud_sel_pressed(LiVESButton * button,livespointer user_data)3653 static void rb_aud_sel_pressed(LiVESButton * button, livespointer user_data) {
3654   aud_dialog_t *audd = (aud_dialog_t *)user_data;
3655   audd->is_sel = !audd->is_sel;
3656   lives_widget_set_sensitive(audd->time_spin, !audd->is_sel);
3657 }
3658 
3659 
create_audfade_dialog(int type)3660 aud_dialog_t *create_audfade_dialog(int type) {
3661   // type 0 = fade in
3662   // type 1 = fade out
3663 
3664   LiVESWidget *dialog_vbox;
3665   LiVESWidget *hbox;
3666   LiVESWidget *rb_sel;
3667   LiVESWidget *label;
3668 
3669   char *label_text = NULL, *label_text2 = NULL, *title;
3670 
3671   double max;
3672 
3673   LiVESSList *radiobutton_group = NULL;
3674 
3675   aud_dialog_t *audd = (aud_dialog_t *)lives_malloc(sizeof(aud_dialog_t));
3676 
3677   if (type == 0) {
3678     title = (_("Fade Audio In"));
3679   } else {
3680     title = (_("Fade Audio Out"));
3681   }
3682 
3683   audd->dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
3684   lives_signal_handlers_disconnect_by_func(audd->dialog, LIVES_GUI_CALLBACK(return_true), NULL);
3685   lives_free(title);
3686 
3687   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(audd->dialog));
3688 
3689   hbox = lives_hbox_new(FALSE, TB_HEIGHT_AUD);
3690   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
3691 
3692 
3693 
3694   if (type == 0) {
3695     label_text = (_("Fade in over  "));
3696     label_text2 = (_("first"));
3697   } else if (type == 1) {
3698     label_text = (_("Fade out over  "));
3699     label_text2 = (_("last"));
3700   }
3701 
3702   label = lives_standard_label_new(label_text);
3703   if (label_text) lives_free(label_text);
3704 
3705   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, 0);
3706 
3707   hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3708   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
3709 
3710   lives_standard_radio_button_new(label_text2, &radiobutton_group, LIVES_BOX(hbox), NULL);
3711 
3712   if (label_text2) lives_free(label_text2);
3713 
3714   max = cfile->laudio_time;
3715 
3716   widget_opts.swap_label = TRUE;
3717   audd->time_spin = lives_standard_spin_button_new(_("seconds."),
3718                     max / 2. > DEF_AUD_FADE_SECS ? DEF_AUD_FADE_SECS : max / 2., .1, max, 1., 10., 2,
3719                     LIVES_BOX(hbox), NULL);
3720   widget_opts.swap_label = FALSE;
3721 
3722   hbox = lives_hbox_new(FALSE, widget_opts.packing_width * 5);
3723   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
3724 
3725   rb_sel = lives_standard_radio_button_new(_("selection"), &radiobutton_group, LIVES_BOX(hbox), NULL);
3726   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rb_sel), FALSE);
3727   audd->is_sel = FALSE;
3728 
3729   if ((cfile->end - 1.) / cfile->fps > cfile->laudio_time) {
3730     // if selection is longer than audio time, we cannot use sel len
3731     lives_widget_set_sensitive(rb_sel, FALSE);
3732   }
3733 
3734   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rb_sel), LIVES_WIDGET_TOGGLED_SIGNAL,
3735                                   LIVES_GUI_CALLBACK(rb_aud_sel_pressed), (livespointer)audd);
3736 
3737   add_fill_to_box(LIVES_BOX(hbox));
3738 
3739   lives_widget_show_all(audd->dialog);
3740 
3741   return audd;
3742 }
3743 
3744 
create_comments_dialog(lives_clip_t * sfile,char * filename)3745 _commentsw *create_comments_dialog(lives_clip_t *sfile, char *filename) {
3746   LiVESWidget *dialog_vbox;
3747   LiVESWidget *table;
3748   LiVESWidget *label;
3749   LiVESWidget *vbox;
3750   LiVESWidget *hbox;
3751   LiVESWidget *buttond;
3752 
3753   char *extrabit, *title;
3754 
3755   _commentsw *commentsw = (_commentsw *)(lives_malloc(sizeof(_commentsw)));
3756 
3757   if (filename) extrabit = (_(" (Optional)"));
3758   else extrabit = lives_strdup("");
3759 
3760   title = lives_strdup_printf(_("File Comments%s"), extrabit);
3761 
3762   commentsw->comments_dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
3763   lives_free(title);
3764   lives_free(extrabit);
3765   lives_signal_handlers_disconnect_by_func(commentsw->comments_dialog, LIVES_GUI_CALLBACK(return_true), NULL);
3766 
3767   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(commentsw->comments_dialog));
3768 
3769   if (filename) {
3770     widget_opts.mnemonic_label = FALSE;
3771     label = lives_standard_label_new((extrabit = lives_strdup_printf(_("File Name: %s"), filename)));
3772     widget_opts.mnemonic_label = TRUE;
3773     lives_free(extrabit);
3774     lives_box_pack_start(LIVES_BOX(dialog_vbox), label, TRUE, TRUE, widget_opts.packing_height);
3775   }
3776 
3777   table = lives_table_new(4, 2, FALSE);
3778   lives_container_set_border_width(LIVES_CONTAINER(table), widget_opts.border_width);
3779 
3780   lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height * 4);
3781 
3782   lives_box_pack_start(LIVES_BOX(dialog_vbox), table, TRUE, TRUE, widget_opts.packing_height);
3783 
3784   label = lives_standard_label_new(_("Title/Name : "));
3785 
3786   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 0, 1, (LiVESAttachOptions)(LIVES_FILL),
3787                      (LiVESAttachOptions)(0), 0, 0);
3788 
3789   label = lives_standard_label_new(_("Author/Artist : "));
3790 
3791   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 1, 2,
3792                      (LiVESAttachOptions)(LIVES_FILL),
3793                      (LiVESAttachOptions)(0), 0, 0);
3794 
3795   label = lives_standard_label_new(_("Comments : "));
3796 
3797   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 3, 4,
3798                      (LiVESAttachOptions)(LIVES_FILL),
3799                      (LiVESAttachOptions)(0), 0, 0);
3800 
3801   commentsw->title_entry = lives_standard_entry_new(NULL, cfile->title, MEDIUM_ENTRY_WIDTH, 1023, NULL, NULL);
3802 
3803   lives_table_attach(LIVES_TABLE(table), commentsw->title_entry, 1, 2, 0, 1,
3804                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
3805                      (LiVESAttachOptions)(LIVES_EXPAND), 0, 0);
3806 
3807   commentsw->author_entry = lives_standard_entry_new(NULL, cfile->author, MEDIUM_ENTRY_WIDTH, 1023, NULL, NULL);
3808 
3809   lives_table_attach(LIVES_TABLE(table), commentsw->author_entry, 1, 2, 1, 2,
3810                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
3811                      (LiVESAttachOptions)(LIVES_EXPAND), 0, 0);
3812 
3813   commentsw->comment_entry = lives_standard_entry_new(NULL, cfile->comment, MEDIUM_ENTRY_WIDTH, 1023, NULL, NULL);
3814 
3815   lives_table_attach(LIVES_TABLE(table), commentsw->comment_entry, 1, 2, 3, 4,
3816                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
3817                      (LiVESAttachOptions)(LIVES_EXPAND), 0, 0);
3818 
3819   if (filename) {
3820     // options
3821     vbox = lives_vbox_new(FALSE, 0);
3822 
3823     add_fill_to_box(LIVES_BOX(vbox));
3824 
3825     hbox = lives_hbox_new(FALSE, 0);
3826     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3827 
3828     commentsw->subt_checkbutton = lives_standard_check_button_new(_("Save _subtitles to file"), FALSE, LIVES_BOX(hbox), NULL);
3829 
3830     if (!sfile->subt) {
3831       lives_widget_set_sensitive(commentsw->subt_checkbutton, FALSE);
3832     } else lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(commentsw->subt_checkbutton), TRUE);
3833 
3834     hbox = lives_hbox_new(FALSE, 0);
3835     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3836 
3837     commentsw->subt_entry = lives_standard_entry_new(_("Subtitle file"), NULL, SHORT_ENTRY_WIDTH, -1, LIVES_BOX(hbox), NULL);
3838 
3839     buttond = lives_standard_button_new_with_label(_("Browse..."), DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
3840 
3841     lives_signal_sync_connect(buttond, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(on_save_subs_activate),
3842                               (livespointer)commentsw->subt_entry);
3843 
3844     lives_box_pack_start(LIVES_BOX(hbox), buttond, FALSE, FALSE, widget_opts.packing_width);
3845 
3846     add_fill_to_box(LIVES_BOX(vbox));
3847 
3848     if (!sfile->subt) {
3849       lives_widget_set_sensitive(commentsw->subt_entry, FALSE);
3850       lives_widget_set_sensitive(buttond, FALSE);
3851     } else {
3852       char xfilename[512];
3853       char *osubfname = NULL;
3854 
3855       lives_snprintf(xfilename, 512, "%s", filename);
3856       get_filename(xfilename, FALSE); // strip extension
3857       switch (sfile->subt->type) {
3858       case SUBTITLE_TYPE_SRT:
3859         osubfname = lives_strdup_printf("%s.%s", xfilename, LIVES_FILE_EXT_SRT);
3860         break;
3861 
3862       case SUBTITLE_TYPE_SUB:
3863         osubfname = lives_strdup_printf("%s.%s", xfilename, LIVES_FILE_EXT_SUB);
3864         break;
3865 
3866       default:
3867         break;
3868       }
3869       lives_entry_set_text(LIVES_ENTRY(commentsw->subt_entry), osubfname);
3870       mainw->subt_save_file = osubfname; // assign instead of free
3871     }
3872 
3873     lives_widget_set_size_request(vbox, ENC_DETAILS_WIN_H, ENC_DETAILS_WIN_V);
3874     lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
3875     lives_standard_expander_new(_("_Options"), LIVES_BOX(dialog_vbox), vbox);
3876   }
3877 
3878   lives_widget_show_all(commentsw->comments_dialog);
3879 
3880   return commentsw;
3881 }
3882 
3883 
3884 static char last_good_folder[PATH_MAX];
3885 
chooser_check_dir(LiVESFileChooser * chooser,livespointer user_data)3886 static void chooser_check_dir(LiVESFileChooser * chooser, livespointer user_data) {
3887   char *cwd = lives_get_current_dir();
3888   char *new_dir;
3889 
3890 #ifdef GUI_GTK
3891   new_dir = gtk_file_chooser_get_current_folder(chooser);
3892 #endif
3893 #ifdef GUI_QT
3894   QFileDialog *qchooser = static_cast<QFileDialog *>(chooser);
3895   new_dir = qchooser->directory().path().toLocal8Bit().data();
3896 #endif
3897 
3898   if (!lives_strcmp(new_dir, last_good_folder)) {
3899     lives_free(cwd);
3900     return;
3901   }
3902 
3903   if (lives_chdir(new_dir, TRUE)) {
3904     lives_free(cwd);
3905 #ifdef GUI_GTK
3906     gtk_file_chooser_set_current_folder(chooser, last_good_folder);
3907 #endif
3908 #ifdef GUI_QT
3909     qchooser->setDirectory(last_good_folder);
3910 #endif
3911     do_dir_perm_access_error(new_dir);
3912     lives_free(new_dir);
3913     return;
3914   }
3915   lives_snprintf(last_good_folder, PATH_MAX, "%s", new_dir);
3916   lives_chdir(cwd, FALSE);
3917   lives_free(new_dir);
3918   lives_free(cwd);
3919 }
3920 
3921 
3922 /**
3923    @brief callback for lives_standard filesel button
3924    same callback is used for dierctory buttons
3925    object_data in button refinses the behaviousr, see code for details
3926 
3927    such buttons may be created independently (e.g for the RFX "fileread" / "filewrite" special types
3928    or via lives_standard_direntry_new() / lives_standard_fileentry_new()
3929 */
on_filesel_button_clicked(LiVESButton * button,livespointer user_data)3930 void on_filesel_button_clicked(LiVESButton * button, livespointer user_data) {
3931   LiVESWidget *tentry = LIVES_WIDGET(user_data);
3932   lives_rfx_t *rfx;
3933   char **filt = NULL;
3934   char *dirname = NULL, *fname, *tmp, *def_dir = NULL;
3935   boolean is_dir = TRUE, free_def_dir = FALSE;
3936   int filesel_type = LIVES_FILE_SELECTION_UNDEFINED;
3937 
3938   if (button) {
3939     /// various data can be set in the button object, including:
3940     /// (set in lives_standard_file_button_new())
3941     /// DEFDIR_KEY (char *)
3942     /// ISDIR_KEY (boolean)
3943     ///
3944     /// FILTER_KEY (char **)
3945     /// FILESEL_TYPE_KEY (int (enum))
3946 
3947     // selects between file mode and directory mode
3948     is_dir = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), ISDIR_KEY));
3949 
3950     // default dir for directory mode
3951     def_dir = (char *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), DEFDIR_KEY);
3952 
3953     /// NULL terminated array of char * filters (file extensions)
3954     filt = (char **)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), FILTER_KEY);
3955 
3956     /// fine tunes for the file selection / dir selection target
3957     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), FILESEL_TYPE_KEY)) {
3958       filesel_type = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), FILESEL_TYPE_KEY));
3959     }
3960   }
3961 
3962   /// take the filename from the text entry widget
3963   if (LIVES_IS_TEXT_VIEW(tentry)) fname = lives_text_view_get_text(LIVES_TEXT_VIEW(tentry));
3964   else fname = lives_strdup(lives_entry_get_text(LIVES_ENTRY(tentry)));
3965 
3966   /// TODO: only do this for directory mode, blank text is valid filename
3967   if (is_dir) {
3968     /// if no text, we look instead in def_dir (if present)
3969     if (!*fname) {
3970       lives_free(fname);
3971       fname = def_dir;
3972     }
3973   }
3974 
3975   /// can this be removed ?
3976   lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
3977 
3978   switch (filesel_type) {
3979   case LIVES_FILE_SELECTION_UNDEFINED:
3980     if (!is_dir && *fname && (!def_dir || !(*def_dir))) {
3981       def_dir = get_dir(fname);
3982       free_def_dir = TRUE;
3983     }
3984 
3985     dirname = choose_file(is_dir ? fname : def_dir, is_dir ? NULL : fname, filt,
3986                           is_dir ? LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER :
3987                           (fname == def_dir && def_dir && !lives_strcmp(def_dir, LIVES_DEVICE_DIR))
3988                           ? LIVES_FILE_CHOOSER_ACTION_SELECT_DEVICE :
3989                           LIVES_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
3990     break;
3991 
3992   case LIVES_DIR_SELECTION_CREATE_FOLDER:
3993     dirname = choose_file(fname, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_CREATE_FOLDER, NULL, NULL);
3994     break;
3995   case LIVES_DIR_SELECTION_SELECT_FOLDER:
3996     dirname = choose_file(fname, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER, NULL, NULL);
3997     break;
3998   case LIVES_DIR_SELECTION_WORKDIR:
3999     dirname = choose_file(fname, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_CREATE_FOLDER, NULL, NULL);
4000 
4001     if (strcmp(dirname, fname)) {
4002       /// apply extra validity checks (check writeable, warn if set to home dir, etc)
4003       if (check_workdir_valid(&dirname, LIVES_DIALOG(lives_widget_get_toplevel(LIVES_WIDGET(button))),
4004                               FALSE) == LIVES_RESPONSE_RETRY) {
4005         lives_free(dirname);
4006         dirname = lives_strdup(fname);
4007       }
4008     }
4009     break;
4010   case LIVES_FILE_SELECTION_OPEN:
4011   case LIVES_FILE_SELECTION_SAVE: {
4012     char fnamex[PATH_MAX], dirnamex[PATH_MAX];
4013     boolean free_filt = FALSE;
4014 
4015     lives_snprintf(dirnamex, PATH_MAX, "%s", fname);
4016     lives_snprintf(fnamex, PATH_MAX, "%s", fname);
4017 
4018     get_dirname(dirnamex);
4019     get_basename(fnamex);
4020 
4021     if (!is_dir && !filt && *fnamex) {
4022       /// for save and not is_dir, we break filename into directory, filename components
4023       /// and set a filter with the filename extension (can be overridden by setting FILTER_KEY)
4024       char *tmp;
4025       filt = (char **)lives_malloc(2 * sizeof(char *));
4026       filt[0] = lives_strdup_printf("*.%s", (tmp = get_extension(fnamex)));
4027       filt[1] = NULL;
4028       free_filt = TRUE;
4029       lives_free(tmp);
4030     }
4031 
4032     dirname = choose_file(def_dir ? def_dir : dirnamex, fnamex, filt, LIVES_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
4033 
4034     if (filesel_type == LIVES_FILE_SELECTION_OPEN);
4035 
4036     if (free_filt) {
4037       lives_free(filt[0]);
4038       lives_free(filt);
4039     }
4040   }
4041   break;
4042 
4043   default: {
4044     /// other types get a filechooser with preview
4045     LiVESWidget *chooser = choose_file_with_preview(def_dir, fname, filt, filesel_type);
4046     int resp = lives_dialog_run(LIVES_DIALOG(chooser));
4047 
4048     end_fs_preview();
4049 
4050     if (resp == LIVES_RESPONSE_ACCEPT) {
4051       dirname = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(chooser));
4052     }
4053     lives_widget_destroy(LIVES_WIDGET(chooser));
4054   }
4055   }
4056 
4057   if (fname && fname != def_dir) lives_free(fname);
4058   if (free_def_dir) lives_free(def_dir);
4059 
4060   /// we set dirname in both file mode and dir mode
4061   if (!dirname) return;
4062 
4063   /// update text widget
4064   if (LIVES_IS_ENTRY(tentry)) lives_entry_set_text(LIVES_ENTRY(tentry),
4065         (tmp = lives_filename_to_utf8(dirname, -1, NULL, NULL, NULL)));
4066   else lives_text_view_set_text(LIVES_TEXT_VIEW(tentry), (tmp = lives_filename_to_utf8(dirname, -1, NULL, NULL, NULL)), -1);
4067   lives_free(tmp); lives_free(dirname);
4068 
4069   if ((rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(tentry), "rfx")) != NULL) {
4070     /// if running inside a parameter window, reflect update in related paramter values
4071     int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(tentry), "param_number"));
4072     after_param_text_changed(tentry, rfx);
4073 
4074     /// set to FALSE since no unapplied edits have been made
4075     rfx->params[param_number].edited = FALSE;
4076   }
4077 }
4078 
4079 
choose_file(const char * dir,const char * fname,char ** const filt,LiVESFileChooserAction act,const char * title,LiVESWidget * extra_widget)4080 char *choose_file(const char *dir, const char *fname, char **const filt, LiVESFileChooserAction act,
4081                   const char *title, LiVESWidget * extra_widget) {
4082   // new style file chooser
4083 
4084   // in/out values are in utf8 encoding
4085   LiVESWidget *chooser;
4086 
4087   char *mytitle;
4088   char *filename = NULL;
4089 
4090   int response;
4091   int i;
4092 
4093   if (!title) {
4094     if (act == LIVES_FILE_CHOOSER_ACTION_SELECT_DEVICE) {
4095       mytitle = lives_strdup_printf(_("%sChoose a Device"), widget_opts.title_prefix);
4096       act = LIVES_FILE_CHOOSER_ACTION_OPEN;
4097     } else if (act == LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER) {
4098       mytitle = lives_strdup_printf(_("%sChoose a Directory"), widget_opts.title_prefix);
4099     } else {
4100       mytitle = lives_strdup_printf(_("%sChoose a File"), widget_opts.title_prefix);
4101     }
4102   } else mytitle = lives_strdup_printf("%s%s", widget_opts.title_prefix, title);
4103 
4104 #ifdef GUI_GTK
4105   if (act != LIVES_FILE_CHOOSER_ACTION_SAVE) {
4106     const char *stocklabel;
4107     if (act == LIVES_FILE_CHOOSER_ACTION_OPEN) {
4108       stocklabel = LIVES_STOCK_LABEL_OPEN;
4109     } else stocklabel = LIVES_STOCK_LABEL_SELECT;
4110     chooser = gtk_file_chooser_dialog_new(mytitle, LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), (LiVESFileChooserAction)act,
4111                                           LIVES_STOCK_LABEL_CANCEL, LIVES_RESPONSE_CANCEL,
4112                                           stocklabel, LIVES_RESPONSE_ACCEPT, NULL);
4113   } else {
4114     chooser = gtk_file_chooser_dialog_new(mytitle, LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), (LiVESFileChooserAction)act,
4115                                           LIVES_STOCK_LABEL_CANCEL, LIVES_RESPONSE_CANCEL,
4116                                           LIVES_STOCK_LABEL_SAVE, LIVES_RESPONSE_ACCEPT, NULL);
4117   }
4118 
4119   if (dir) {
4120     gtk_file_chooser_set_current_folder(LIVES_FILE_CHOOSER(chooser), dir);
4121   }
4122 
4123   lives_widget_show_all(chooser);
4124 
4125   if (prefs->fileselmax) {
4126     lives_window_maximize(LIVES_WINDOW(chooser));
4127   }
4128 
4129   gtk_file_chooser_set_local_only(LIVES_FILE_CHOOSER(chooser), TRUE);
4130 
4131   if (filt) {
4132     GtkFileFilter *filter = gtk_file_filter_new();
4133     for (i = 0; filt[i]; i++) gtk_file_filter_add_pattern(filter, filt[i]);
4134     gtk_file_chooser_set_filter(LIVES_FILE_CHOOSER(chooser), filter);
4135     if (i == 1 && act == LIVES_FILE_CHOOSER_ACTION_SAVE)
4136       gtk_file_chooser_set_current_name(LIVES_FILE_CHOOSER(chooser), filt[0]); //utf-8
4137   }
4138 
4139   if (fname) {
4140     if (act == LIVES_FILE_CHOOSER_ACTION_SAVE || act == LIVES_FILE_CHOOSER_ACTION_CREATE_FOLDER) { // prevent assertion in gtk+
4141       gtk_file_chooser_set_current_name(LIVES_FILE_CHOOSER(chooser), fname); // utf-8
4142       if (fname && dir) {
4143         char *ffname = lives_build_filename(dir, fname, NULL);
4144         gtk_file_chooser_select_filename(LIVES_FILE_CHOOSER(chooser), ffname); // must be dir and file
4145         lives_free(ffname);
4146       }
4147     }
4148   }
4149 
4150   /* if (extra_widget && extra_widget != LIVES_MAIN_WINDOW_WIDGET) { */
4151   /*   gtk_file_chooser_set_extra_widget(LIVES_FILE_CHOOSER(chooser), extra_widget); */
4152   /*   if (palette->style & STYLE_1) { */
4153   /*     LiVESWidget *parent = lives_widget_get_parent(extra_widget); */
4154 
4155   /*     while (parent) { */
4156   /*       lives_widget_set_fg_color(parent, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore); */
4157   /*       lives_widget_set_bg_color(parent, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back); */
4158   /*       parent = lives_widget_get_parent(parent); */
4159   /*     } */
4160   /*   } */
4161   /* } */
4162 
4163   if (mainw->is_ready && palette->style & STYLE_1) {
4164     lives_widget_set_bg_color(chooser, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
4165     lives_widget_set_fg_color(chooser, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
4166     set_child_colour(chooser, FALSE);
4167   }
4168 
4169 #endif
4170 
4171   lives_container_set_border_width(LIVES_CONTAINER(chooser), widget_opts.border_width);
4172 
4173   if (prefs->show_gui) {
4174     LiVESWindow *transient = widget_opts.transient;
4175     if (!transient) transient = get_transient_full();
4176     if (transient)
4177       lives_window_set_transient_for(LIVES_WINDOW(chooser), transient);
4178   }
4179 
4180   lives_signal_sync_connect(chooser, LIVES_WIDGET_CURRENT_FOLDER_CHANGED_SIGNAL, LIVES_GUI_CALLBACK(chooser_check_dir), NULL);
4181   //lives_widget_grab_focus(chooser);
4182   lives_window_center(LIVES_WINDOW(chooser));
4183   lives_window_set_modal(LIVES_WINDOW(chooser), TRUE);
4184   lives_memset(last_good_folder, 0, 1);
4185 
4186   //set this so we know when button is pressed, even if waiting for preview to finish
4187   mainw->fc_buttonresponse = LIVES_RESPONSE_NONE;
4188   //lives_signal_sync_connect(chooser, LIVES_WIDGET_RESPONSE_SIGNAL, LIVES_GUI_CALLBACK(chooser_response), NULL);
4189 
4190   if (dir) {
4191     gtk_file_chooser_set_current_folder(LIVES_FILE_CHOOSER(chooser), dir);
4192     gtk_file_chooser_add_shortcut_folder(LIVES_FILE_CHOOSER(chooser), dir, NULL);
4193   }
4194 
4195   if (extra_widget == LIVES_MAIN_WINDOW_WIDGET && LIVES_MAIN_WINDOW_WIDGET) {
4196     return (char *)chooser; // kludge to allow custom adding of extra widgets
4197   }
4198 
4199 rundlg:
4200   if ((response = lives_dialog_run(LIVES_DIALOG(chooser))) != LIVES_RESPONSE_CANCEL) {
4201     char *tmp;
4202     filename = lives_filename_to_utf8((tmp = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(chooser))),
4203                                       -1, NULL, NULL, NULL);
4204     lives_free(tmp);
4205   } else filename = NULL;
4206 
4207   if (response && filename && act == LIVES_FILE_CHOOSER_ACTION_SAVE) {
4208     if (!check_file(filename, TRUE)) {
4209       lives_free(filename);
4210       filename = NULL;
4211       goto rundlg;
4212     }
4213   }
4214 
4215   lives_free(mytitle);
4216   lives_widget_destroy(chooser);
4217   mainw->fc_buttonresponse = response;
4218   return filename;
4219 }
4220 
choose_file_bg(const char * dir,const char * fname,char ** const filt,LiVESFileChooserAction act,const char * title,LiVESWidget * extra_widget)4221 char *choose_file_bg(const char *dir, const char *fname, char **const filt, LiVESFileChooserAction act,
4222                      const char *title, LiVESWidget * extra_widget) {
4223   return main_thread_execute((lives_funcptr_t)choose_file, WEED_SEED_STRING,
4224                              NULL, "ssvisv", dir, fname, filt, act, title, extra_widget);
4225 }
4226 
4227 
choose_file_with_preview(const char * dir,const char * title,char ** const filt,int filesel_type)4228 LiVESWidget *choose_file_with_preview(const char *dir, const char *title, char **const filt, int filesel_type) {
4229   // filesel_type 1 - video and audio open (single - opensel)
4230   //LIVES_FILE_SELECTION_VIDEO_AUDIO
4231 
4232   // preview type 2 - import audio
4233   // LIVES_FILE_SELECTION_AUDIO_ONLY
4234 
4235   // filesel_type 3 - video and audio open (multiple)
4236   //LIVES_FILE_SELECTION_VIDEO_AUDIO_MULTI
4237 
4238   // type 4
4239   // LIVES_FILE_SELECTION_VIDEO_RANGE
4240 
4241   // type 5
4242   // LIVES_FILE_SELECTION_IMAGE_ONLY
4243 
4244   // unfortunately we cannot simply run this and return a filename, in case there is a selection
4245 
4246   LiVESWidget *chooser;
4247 
4248   int preview_type;
4249 
4250   if (filesel_type == LIVES_DIR_SELECTION_CREATE_FOLDER) {
4251     chooser = (LiVESWidget *)choose_file(dir, NULL, filt, LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER,
4252                                          title, LIVES_MAIN_WINDOW_WIDGET);
4253     gtk_file_chooser_set_create_folders(LIVES_FILE_CHOOSER(chooser), TRUE);
4254   } else if (filesel_type == LIVES_DIR_SELECTION_SELECT_FOLDER)
4255     chooser = (LiVESWidget *)choose_file(dir, NULL, filt, LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER,
4256                                          title, LIVES_MAIN_WINDOW_WIDGET);
4257 
4258   chooser = (LiVESWidget *)choose_file(dir, NULL, filt, LIVES_FILE_CHOOSER_ACTION_OPEN, title, LIVES_MAIN_WINDOW_WIDGET);
4259 
4260   if (filesel_type == LIVES_FILE_SELECTION_VIDEO_AUDIO_MULTI) {
4261 #ifdef GUI_GTK
4262     gtk_file_chooser_set_select_multiple(LIVES_FILE_CHOOSER(chooser), TRUE);
4263 #endif
4264   }
4265 
4266   switch (filesel_type) {
4267   case LIVES_FILE_SELECTION_VIDEO_AUDIO:
4268   case LIVES_FILE_SELECTION_VIDEO_AUDIO_MULTI:
4269     preview_type = LIVES_PREVIEW_TYPE_VIDEO_AUDIO;
4270     break;
4271   case LIVES_FILE_SELECTION_IMAGE_ONLY:
4272     preview_type = LIVES_PREVIEW_TYPE_IMAGE_ONLY;
4273     break;
4274   default:
4275     preview_type = LIVES_PREVIEW_TYPE_AUDIO_ONLY;
4276   }
4277 
4278   widget_add_preview(chooser, LIVES_BOX(lives_dialog_get_content_area(LIVES_DIALOG(chooser))),
4279                      LIVES_BOX(lives_dialog_get_content_area(LIVES_DIALOG(chooser))),
4280                      LIVES_BOX(lives_dialog_get_action_area(LIVES_DIALOG(chooser))),
4281                      preview_type);
4282 
4283   if (prefs->fileselmax) {
4284     int scr_width = GUI_SCREEN_WIDTH;
4285     int scr_height = GUI_SCREEN_HEIGHT;
4286     int bx, by, w, h;
4287 
4288     lives_widget_show_all(chooser);
4289     lives_widget_process_updates(chooser);
4290 
4291     get_border_size(chooser, &bx, &by);
4292     w = lives_widget_get_allocation_width(chooser);
4293     h = lives_widget_get_allocation_height(chooser);
4294 
4295     if (w > scr_width - bx || h > scr_height - by) {
4296       if (w > scr_width - bx || h > scr_height - by) {
4297         int overflowx = w - (scr_width - bx);
4298         int overflowy = h - (scr_height - by);
4299 
4300         int mywidth = lives_widget_get_allocation_width(chooser);
4301         int myheight = lives_widget_get_allocation_height(chooser);
4302 
4303 #ifdef DEBUG_OVERFLOW
4304         g_print("overflow is %d X %d\n", overflowx, overflowy);
4305 #endif
4306         if (overflowx > 0) mywidth -= overflowx;
4307         if (overflowy > 0) myheight -= overflowy;
4308 
4309         lives_widget_process_updates(chooser);
4310 
4311         if (overflowx > 0 || overflowy > 0) {
4312           lives_widget_set_size_request(chooser, mywidth, myheight);
4313         }
4314         lives_widget_process_updates(chooser);
4315 
4316         w = scr_width - bx;
4317         h = scr_height - by;
4318 
4319         lives_window_unmaximize(LIVES_WINDOW(chooser));
4320         lives_widget_process_updates(chooser);
4321         lives_window_resize(LIVES_WINDOW(chooser), w, h);
4322         lives_widget_process_updates(chooser);
4323 
4324         if (prefs->open_maximised) {
4325           lives_window_maximize(LIVES_WINDOW(chooser));
4326         }
4327       }
4328     } else {
4329       lives_window_maximize(LIVES_WINDOW(chooser));
4330     }
4331     lives_widget_process_updates(chooser);
4332   }
4333   return chooser;
4334 }
4335 
4336 /* LiVESWidget *choose_file_with_preview(const char *dir, const char *title, char **const filt, int filesel_type) { */
4337 /*   return main_thread_execute((lives_funcptr_t)_choose_file_with_preview, WEED_SEED_STRING, */
4338 /*                              NULL, "ssvi", dir, title, filt, filesel_type); */
4339 /* } */
4340 
4341 
make_autoreload_check(LiVESHBox * hbox,boolean is_active)4342 LIVES_GLOBAL_INLINE LiVESWidget *make_autoreload_check(LiVESHBox * hbox, boolean is_active) {
4343   return lives_standard_check_button_new(_("_Autoreload next time"), is_active, LIVES_BOX(hbox), NULL);
4344 }
4345 
4346 
4347 //cancel/discard/save dialog
create_cds_dialog(int type)4348 _entryw *create_cds_dialog(int type) {
4349   // values for type are:
4350   // 0 == leave multitrack, user pref is warn when leave multitrack
4351   // 1 == exit from LiVES, or save set
4352   // 2 == ?
4353   // 3 == wipe layout confirmation
4354   // 4 == prompt for render after recording / viewing in mt
4355 
4356   LiVESWidget *dialog_vbox;
4357   LiVESWidget *cancelbutton;
4358   LiVESWidget *discardbutton;
4359   LiVESWidget *savebutton = NULL;
4360 
4361   LiVESAccelGroup *accel_group;
4362 
4363   char *labeltext = NULL;
4364 
4365   _entryw *cdsw = (_entryw *)(lives_malloc(sizeof(_entryw)));
4366 
4367   cdsw->warn_checkbutton = NULL;
4368 
4369   if (type == 0) {
4370     if (!*mainw->multitrack->layout_name) {
4371       labeltext = lives_strdup(
4372                     _("You are about to leave multitrack mode.\n"
4373                       "The current layout has not been saved.\nWhat would you like to do ?\n"));
4374     } else {
4375       labeltext = lives_strdup(
4376                     _("You are about to leave multitrack mode.\n"
4377                       "The current layout has been changed since the last save.\n"
4378                       "What would you like to do ?\n"));
4379     }
4380   } else if (type == 1) {
4381     if (!mainw->only_close) labeltext = lives_strdup(
4382                                             _("You are about to exit LiVES.\n"
4383                                               "The current clip set can be saved.\n"
4384                                               "What would you like to do ?\n"));
4385     else labeltext = (_("The current clip set has not been saved.\nWhat would you like to do ?\n"));
4386   } else if (type == 2 || type == 3) {
4387     if ((mainw->multitrack && mainw->multitrack->changed) || (mainw->stored_event_list &&
4388         mainw->stored_event_list_changed)) {
4389       labeltext = (_("The current layout has not been saved.\nWhat would you like to do ?\n"));
4390     } else {
4391       labeltext = lives_strdup(
4392                     _("The current layout has *NOT BEEN CHANGED* since it was last saved.\n"
4393                       "What would you like to do ?\n"));
4394     }
4395   } else if (type == 4) {
4396     labeltext = lives_strdup(
4397                   _("You are about to leave multitrack mode.\n"
4398                     "The current layout contains generated frames and cannot be retained.\n"
4399                     "What do you wish to do ?"));
4400   }
4401 
4402   cdsw->dialog = create_question_dialog(_("Save or Delete Set"), labeltext);
4403 
4404   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(cdsw->dialog));
4405 
4406   if (labeltext) lives_free(labeltext);
4407 
4408   if (type == 1) {
4409     LiVESWidget *checkbutton;
4410     LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
4411     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
4412 
4413     cdsw->entry = lives_standard_entry_new(_("Clip set _name"), strlen(mainw->set_name)
4414                                            ? mainw->set_name : "",
4415                                            SHORT_ENTRY_WIDTH, 128, LIVES_BOX(hbox), NULL);
4416 
4417     hbox = lives_hbox_new(FALSE, 0);
4418     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
4419 
4420     prefs->ar_clipset = !mainw->only_close;
4421     checkbutton = make_autoreload_check(LIVES_HBOX(hbox), prefs->ar_clipset);
4422 
4423     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(checkbutton), "cdsw", (livespointer)cdsw);
4424 
4425     lives_signal_sync_connect(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4426                               LIVES_GUI_CALLBACK(toggle_sets_pref),
4427                               (livespointer)PREF_AR_CLIPSET);
4428   }
4429 
4430   if (type == 0 && !(prefs->warning_mask & WARN_MASK_EXIT_MT)) {
4431     add_warn_check(LIVES_BOX(dialog_vbox), WARN_MASK_EXIT_MT);
4432   }
4433 
4434   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
4435   lives_window_add_accel_group(LIVES_WINDOW(cdsw->dialog), accel_group);
4436 
4437   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(cdsw->dialog), LIVES_STOCK_CANCEL, NULL,
4438                  LIVES_RESPONSE_CANCEL);
4439 
4440   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
4441                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
4442 
4443   discardbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(cdsw->dialog), LIVES_STOCK_DELETE, NULL,
4444                   (type == 2) ? LIVES_RESPONSE_ABORT : LIVES_RESPONSE_RESET);
4445 
4446   if ((type == 0 && !*mainw->multitrack->layout_name) || type == 3 || type == 4)
4447     lives_button_set_label(LIVES_BUTTON(discardbutton), _("_Wipe layout"));
4448   else if (type == 0) lives_button_set_label(LIVES_BUTTON(discardbutton), _("_Ignore changes"));
4449   else if (type == 1) {
4450     if (mainw->was_set)
4451       lives_button_set_label(LIVES_BUTTON(discardbutton), _("_Delete clip set"));
4452     else
4453       lives_button_set_label(LIVES_BUTTON(discardbutton), _("_Discard all clips"));
4454   } else if (type == 2) lives_button_set_label(LIVES_BUTTON(discardbutton), _("_Delete layout"));
4455 
4456   if (type != 4) savebutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(cdsw->dialog), LIVES_STOCK_SAVE, NULL,
4457                                 (type == 2) ? LIVES_RESPONSE_RETRY : LIVES_RESPONSE_ACCEPT);
4458   if (type == 0 || type == 3) lives_button_set_label(LIVES_BUTTON(savebutton), _("_Save layout"));
4459   else if (type == 1) lives_button_set_label(LIVES_BUTTON(savebutton), _("_Save clip set"));
4460   else if (type == 2) lives_button_set_label(LIVES_BUTTON(savebutton), _("_Wipe layout"));
4461   if (type == 1 || type == 2) lives_button_grab_default_special(savebutton);
4462 
4463   lives_widget_show_all(cdsw->dialog);
4464 
4465   if (type == 1) {
4466     lives_widget_grab_focus(cdsw->entry);
4467   }
4468 
4469   if (!LIVES_IS_INTERACTIVE) lives_widget_set_sensitive(cancelbutton, FALSE);
4470 
4471   return cdsw;
4472 }
4473 
4474 
flip_cdisk_bit(LiVESToggleButton * t,livespointer user_data)4475 static void flip_cdisk_bit(LiVESToggleButton * t, livespointer user_data) {
4476   uint32_t bitmask = LIVES_POINTER_TO_INT(user_data);
4477   prefs->clear_disk_opts ^= bitmask;
4478 }
4479 
4480 
create_cleardisk_advanced_dialog(void)4481 LiVESWidget *create_cleardisk_advanced_dialog(void) {
4482   LiVESWidget *dialog;
4483   LiVESWidget *dialog_vbox;
4484   LiVESWidget *scrollw;
4485   LiVESWidget *vbox;
4486   LiVESWidget *hbox;
4487   LiVESWidget *checkbutton;
4488   LiVESWidget *okbutton;
4489 
4490   int woat = widget_opts.apply_theme;
4491 
4492   char *tmp, *tmp2;
4493 
4494   dialog = lives_standard_dialog_new(_("Disk Recovery Options"), FALSE, DEF_DIALOG_WIDTH, DEF_DIALOG_HEIGHT);
4495 
4496   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
4497 
4498   vbox = lives_vbox_new(FALSE, 0);
4499   lives_container_set_border_width(LIVES_CONTAINER(vbox), widget_opts.border_width * 2);
4500 
4501   widget_opts.apply_theme = 0;
4502   scrollw = lives_standard_scrolled_window_new(DEF_DIALOG_WIDTH, DEF_DIALOG_HEIGHT, vbox);
4503   widget_opts.apply_theme = woat;
4504 
4505   lives_container_add(LIVES_CONTAINER(dialog_vbox), scrollw);
4506 
4507   hbox = lives_hbox_new(FALSE, 0);
4508   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, widget_opts.packing_height);
4509 
4510   checkbutton = lives_standard_check_button_new((tmp = (_("Check for Lost Clips"))),
4511                 !(prefs->clear_disk_opts & LIVES_CDISK_REMOVE_ORPHAN_CLIPS), LIVES_BOX(hbox),
4512                 (tmp2 = (H_("Enable attempted recovery of potential lost clips before deleting them.\n"
4513                             "Can be overriden after disk analysis."))));
4514 
4515   lives_free(tmp); lives_free(tmp2);
4516 
4517   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4518                                   LIVES_GUI_CALLBACK(flip_cdisk_bit),
4519                                   LIVES_INT_TO_POINTER(LIVES_CDISK_REMOVE_ORPHAN_CLIPS));
4520 
4521   hbox = lives_hbox_new(FALSE, 0);
4522   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, widget_opts.packing_height);
4523 
4524   checkbutton = lives_standard_check_button_new((tmp = (_("Remove Empty Directories"))),
4525                 !(prefs->clear_disk_opts & LIVES_CDISK_LEAVE_EMPTY_DIRS), LIVES_BOX(hbox),
4526                 (tmp2 = (H_("Remove any empty directories within the working directory"))));
4527 
4528   lives_free(tmp); lives_free(tmp2);
4529 
4530   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4531                                   LIVES_GUI_CALLBACK(flip_cdisk_bit),
4532                                   LIVES_INT_TO_POINTER(LIVES_CDISK_LEAVE_ORPHAN_SETS));
4533 
4534   hbox = lives_hbox_new(FALSE, 0);
4535   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, widget_opts.packing_height);
4536 
4537   checkbutton = lives_standard_check_button_new((tmp = (_("Delete _Orphaned Clips"))),
4538                 !(prefs->clear_disk_opts & LIVES_CDISK_LEAVE_ORPHAN_SETS), LIVES_BOX(hbox),
4539                 (tmp2 = (H_("Delete any clips which are not currently loaded or part of a set\n"
4540                             "If 'Check for Lost Clips' is set, LiVES will try to recover them first"))));
4541 
4542   lives_free(tmp); lives_free(tmp2);
4543 
4544   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4545                                   LIVES_GUI_CALLBACK(flip_cdisk_bit),
4546                                   LIVES_INT_TO_POINTER(LIVES_CDISK_LEAVE_ORPHAN_SETS));
4547 
4548   hbox = lives_hbox_new(FALSE, 0);
4549   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, widget_opts.packing_height);
4550 
4551   checkbutton = lives_standard_check_button_new(_("Clear Useless  _Backup Files from Clips"),
4552                 !(prefs->clear_disk_opts & LIVES_CDISK_LEAVE_BFILES), LIVES_BOX(hbox), NULL);
4553 
4554   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4555                                   LIVES_GUI_CALLBACK(flip_cdisk_bit),
4556                                   LIVES_INT_TO_POINTER(LIVES_CDISK_LEAVE_BFILES));
4557 
4558   hbox = lives_hbox_new(FALSE, 0);
4559   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, widget_opts.packing_height);
4560 
4561   checkbutton = lives_standard_check_button_new(_("Remove Sets which have _Layouts but no Clips"),
4562                 (prefs->clear_disk_opts & LIVES_CDISK_REMOVE_ORPHAN_LAYOUTS), LIVES_BOX(hbox), NULL);
4563 
4564   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
4565                                   LIVES_GUI_CALLBACK(flip_cdisk_bit),
4566                                   LIVES_INT_TO_POINTER(LIVES_CDISK_REMOVE_ORPHAN_LAYOUTS));
4567 
4568   // resetbutton
4569   lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_REFRESH, _("_Reset to Defaults"),
4570                                      LIVES_RESPONSE_RETRY);
4571 
4572   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL,
4573              LIVES_RESPONSE_OK);
4574 
4575   lives_button_grab_default_special(okbutton);
4576 
4577   return dialog;
4578 }
4579 
4580 
4581 #ifdef GTK_TEXT_VIEW_DRAW_BUG
4582 
4583 static ulong expt;
4584 
exposetview(LiVESWidget * widget,lives_painter_t * cr,livespointer user_data)4585 static boolean exposetview(LiVESWidget * widget, lives_painter_t *cr, livespointer user_data) {
4586   LiVESWidgetColor fgcol, bgcol;
4587   lives_colRGBA64_t fg, bg;
4588   LingoLayout *layout = NULL;
4589   lives_painter_surface_t *surface;
4590   char *text = lives_text_view_get_text(LIVES_TEXT_VIEW(widget));
4591   double top = 0;
4592   int offsx = 0;
4593   int height = lives_widget_get_allocation_height(widget);
4594 
4595   lives_signal_handler_block(widget, expt);
4596 
4597   surface = lives_painter_get_target(cr);
4598   lives_painter_surface_flush(surface);
4599 
4600   lives_widget_get_fg_state_color(widget, lives_widget_get_state(widget), &fgcol);
4601   lives_widget_get_bg_state_color(widget, lives_widget_get_state(widget), &bgcol);
4602 
4603   widget_color_to_lives_rgba(&fg, &fgcol);
4604   widget_color_to_lives_rgba(&bg, &bgcol);
4605 
4606   layout = render_text_to_cr(widget, cr, text, "", 0.0,
4607                              LIVES_TEXT_MODE_FOREGROUND_ONLY, &fg, &bg, FALSE, FALSE, &top, &offsx,
4608                              lives_widget_get_allocation_width(widget), &height);
4609 
4610   lives_free(text);
4611 
4612   if (layout) {
4613     if (LINGO_IS_LAYOUT(layout)) {
4614       lingo_painter_show_layout(cr, layout);
4615     }
4616     lives_widget_object_unref(layout);
4617     //if (LIVES_IS_WIDGET_OBJECT(layout)) lives_widget_object_unref(layout);
4618   }
4619 
4620   //lives_painter_fill(cr);
4621 
4622   lives_signal_handler_unblock(widget, expt);
4623 
4624   return FALSE;
4625 }
4626 
4627 #endif
4628 
4629 
create_output_textview(void)4630 LiVESTextView *create_output_textview(void) {
4631   LiVESWidget *textview = lives_standard_text_view_new(NULL, NULL);
4632 
4633 #ifdef GTK_TEXT_VIEW_DRAW_BUG
4634   expt = lives_signal_sync_connect(LIVES_GUI_OBJECT(textview), LIVES_WIDGET_EXPOSE_EVENT,
4635                                    LIVES_GUI_CALLBACK(exposetview), NULL);
4636 #endif
4637   lives_widget_object_ref(textview);
4638   return LIVES_TEXT_VIEW(textview);
4639 }
4640 
4641 
4642 static int currow;
4643 
pair_add(LiVESWidget * table,const char * key,const char * meaning)4644 static void pair_add(LiVESWidget * table, const char *key, const char *meaning) {
4645   LiVESWidget *labelk, *labelm, *align;
4646   double kalign = 0., malign = 0.;
4647   boolean key_all = FALSE;
4648 
4649   if (!key) {
4650     // NULL, NULL ->  hsep all TODO
4651     if (!meaning) {
4652       labelk = lives_standard_hseparator_new();
4653       key_all = TRUE;
4654     } else {
4655       if (*meaning) {
4656         // NULL, meaning -> centered meaning; hsep key
4657         pair_add(table, meaning, "");
4658         pair_add(table, NULL, "");
4659         return;
4660       } else {
4661         // NULL, "" -> hsep key
4662         labelk = lives_standard_hseparator_new();
4663         labelm = lives_standard_label_new("");
4664       }
4665     }
4666   } else {
4667     if (!*key) {
4668       // "", NULL -> hsep meaning
4669       if (!meaning) {
4670         labelk = lives_standard_label_new("");
4671         labelm = lives_standard_hseparator_new();
4672       } else {
4673         if (!*meaning) {
4674           //// "", "" -> newline
4675           labelk = lives_standard_label_new("");
4676           labelm = lives_standard_label_new("");
4677         } else {
4678           /// "", meaning -> "" | centered meaning
4679           labelk = lives_standard_label_new("");
4680           labelm = lives_standard_label_new(meaning);
4681           malign = .5;
4682         }
4683       }
4684     } else {
4685       // key, NULL ->   all centered key
4686       if (!meaning) {
4687         labelk = lives_standard_label_new(key);
4688         kalign = .5;
4689         key_all = TRUE;
4690       } else {
4691         // key, meaning ->  key | meaning
4692         if (*meaning) {
4693           labelk = lives_standard_label_new(key);
4694           labelm = lives_standard_label_new(meaning);
4695         } else {
4696           // key, "" -> center key
4697           labelk = lives_standard_label_new(key);
4698           labelm = lives_standard_label_new(" ");
4699           kalign = .5;
4700 	  // *INDENT-OFF*
4701         }}}}
4702   // *INDENT-ON*
4703 
4704   align = lives_alignment_new(kalign, .5, 1., 0.);
4705   lives_container_add(LIVES_CONTAINER(align), labelk);
4706 
4707   if (!key_all) {
4708     lives_table_attach(LIVES_TABLE(table), align, 0, 1, currow, currow + 1,
4709                        (LiVESAttachOptions)(LIVES_FILL),
4710                        (LiVESAttachOptions)(0), 0, 0);
4711 
4712     align = lives_alignment_new(malign, .5, 0., 0.);
4713     lives_container_add(LIVES_CONTAINER(align), labelm);
4714 
4715     lives_table_attach(LIVES_TABLE(table), align, 1, 40, currow, currow + 1,
4716                        (LiVESAttachOptions)(LIVES_EXPAND),
4717                        (LiVESAttachOptions)(0), 0, 0);
4718   } else {
4719     lives_table_attach(LIVES_TABLE(table), align, 0, 40, currow, currow + 1,
4720                        (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
4721                        (LiVESAttachOptions)(0), 0, 0);
4722   }
4723 
4724   currow++;
4725 
4726   lives_widget_show_all(table);
4727 }
4728 
4729 
4730 #define ADD_KEYDEF(key, desc) pair_add(textwindow->table, (tmp = lives_strdup(key)), (tmp2 = lives_strdup(desc))); \
4731   lives_free(tmp); lives_free(tmp2)
4732 
do_keys_window(void)4733 void do_keys_window(void) {
4734   char *tmp = (_("Show Keys")), *tmp2;
4735   text_window *textwindow;
4736 
4737   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
4738   textwindow = create_text_window(tmp, NULL, NULL, TRUE);
4739   lives_free(tmp);
4740   widget_opts.expand = LIVES_EXPAND_DEFAULT;;
4741 
4742   lives_table_resize(LIVES_TABLE(textwindow->table), 1, 40);
4743   currow = 0;
4744 
4745   ADD_KEYDEF(_("You can use the following keys during playback to control LiVES:-"), NULL);
4746   ADD_KEYDEF(NULL, NULL);
4747   ADD_KEYDEF(NULL, _("Recordable keys (press 'r' before playback to make a recording)"));
4748   ADD_KEYDEF(_("ctrl-left"), _("skip / scratch backwards (video only)\nWhen not playing moves the playback cursor"));
4749   ADD_KEYDEF(_("ctrl-right"), _("skip / scratch forwards (video only)\nWhen not playing moves the playback cursor"));
4750   ADD_KEYDEF(_("ctrl-up"), _("play faster"));
4751   ADD_KEYDEF(_("ctrl-down"), _("play slower"));
4752   ADD_KEYDEF(_("ctrl-shift-up"), _("background clip play faster"));
4753   ADD_KEYDEF(_("ctrl-shift-down"), _("background clip play slower"));
4754   ADD_KEYDEF(_("ctrl-alt-up"), _("increase effect parameter for keygrabbed effect"));
4755   ADD_KEYDEF(_("ctrl-alt-down"), _("decrease effect parameter for keybrabbed effect"));
4756   ADD_KEYDEF(_("ctrl-enter"), _("reset frame rate / resync audio (foreground clip)"));
4757   ADD_KEYDEF(_("ctrl-shift-enter"), _("reset frame rate (background clip)"));
4758   ADD_KEYDEF(_("ctrl-space"), _("reverse direction (foreground clip)"));
4759   ADD_KEYDEF(_("ctrl-shift-space"), _("reverse direction (background clip)"));
4760   ADD_KEYDEF(_("ctrl-alt-space"),
4761              _("Loop Lock\n(press once to mark IN point, then again to mark OUT point;\n"
4762                "ctrl-space, ctrl-enter, or switching clips clears)"));
4763   ADD_KEYDEF(_("ctrl-backspace"), _("freeze frame (foreground and background)"));
4764   ADD_KEYDEF(_("ctrl-alt-backspace"), _("freeze frame (background clip only)"));
4765   ADD_KEYDEF("a",
4766              _("audio lock ON: lock audio to the current foreground clip;\nignore video clip switches and rate / direction changes"));
4767   ADD_KEYDEF("A", _("audio lock OFF; audio follows the foreground video clip\n(unless overridden in Preferences)"));
4768   ADD_KEYDEF("n", _("nervous mode"));
4769   ADD_KEYDEF(_("ctrl-page-up"), _("previous clip"));
4770   ADD_KEYDEF(_("ctrl-page-down"), _("next clip"));
4771   ADD_KEYDEF("", "");
4772   ADD_KEYDEF(_("ctrl-1"), _("toggle real-time effect 1"));
4773   ADD_KEYDEF(_("ctrl-2"), _("toggle real-time effect 2"));
4774   ADD_KEYDEF(_("...etc..."), "");
4775   ADD_KEYDEF(_("ctrl-9"), _("toggle real-time effect 9"));
4776   ADD_KEYDEF(_("ctrl-0"), _("real-time effects (1 - 9) OFF"));
4777   ADD_KEYDEF(_("ctrl-minus"), _("toggle real-time effect 10 (unaffected by ctrl-0)"));
4778   ADD_KEYDEF(_("ctrl-equals"), _("toggle real-time effect 11 (unaffected by ctrl-0)"));
4779   ADD_KEYDEF("x", _("swap background / foreground clips"));
4780   ADD_KEYDEF("", "");
4781   ADD_KEYDEF("k", _("grab keyboard for last activated effect key\n(affects m, M, t, tab and ctrl-alt-up, ctrl-alt-down keys)"));
4782   ADD_KEYDEF("m", _("next effect mode (for whichever key has keyboard grab)"));
4783   ADD_KEYDEF("M", _("previous effect mode (for whichever key has keyboard grab)"));
4784   ADD_KEYDEF(_("ctrl-alt-1"), _("grab keyboard for effect key 1 (similar to k key)"));
4785   ADD_KEYDEF(_("ctrl-alt-2"), _("grab keyboard for effect key 2"));
4786   ADD_KEYDEF(_("...etc..."), "");
4787   ADD_KEYDEF("t", _("enter text parameter (when effect has keyboard grab)"));
4788   ADD_KEYDEF(_("TAB"), _("leave text parameter (reverse of 't')"));
4789   ADD_KEYDEF(_("F1"), _("store/switch to bookmark 1 (first press stores clip and frame)"));
4790   ADD_KEYDEF(_("F2"), _("store/switch to bookmark 2"));
4791   ADD_KEYDEF(_("...etc..."), "");
4792   ADD_KEYDEF(_("F12"), _("clear function keys (bookmarks)"));
4793   ADD_KEYDEF("", "");
4794   ADD_KEYDEF(NULL, _("Other playback keys"));
4795   ADD_KEYDEF("p", _("play all"));
4796   ADD_KEYDEF("y", _("play selection"));
4797   ADD_KEYDEF("q", _("stop"));
4798   ADD_KEYDEF("f", _("fullscreen"));
4799   ADD_KEYDEF("s", _("separate window"));
4800   ADD_KEYDEF("d", _("double sized playarea (only in clip edit mode)"));
4801   ADD_KEYDEF("r", _("toggle recording mode (clip edit mode only)"));
4802   ADD_KEYDEF("b", _("blank / unblank the interface background (clip editor only)"));
4803   ADD_KEYDEF("o", _("activate / deactivate continuous looping"));
4804   ADD_KEYDEF("g", _("enable / disable ping pong looping"));
4805   ADD_KEYDEF("l", _("enable / disable stop on audio end\n(ignored if continuous loop is active)"));
4806   ADD_KEYDEF("<", _("lower the volume of current audio clip"));
4807   ADD_KEYDEF(">", _("increase the volume of current audio clip"));
4808   ADD_KEYDEF("w", _("display a/v sync status (developer mode)"));
4809   ADD_KEYDEF("", "");
4810 }
4811 
4812 
do_mt_keys_window(void)4813 void do_mt_keys_window(void) {
4814   text_window *textwindow;
4815   char *tmp = (_("Multitrack Keys")), *tmp2;
4816 
4817   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
4818   textwindow = create_text_window(tmp, NULL, NULL, TRUE);
4819   lives_free(tmp);
4820   widget_opts.expand = LIVES_EXPAND_DEFAULT;;
4821 
4822   lives_table_resize(LIVES_TABLE(textwindow->table), 1, 40);
4823   currow = 0;
4824 
4825   ADD_KEYDEF(_("You can use the following keys to control the multitrack window:"), NULL);
4826   ADD_KEYDEF(NULL, NULL);
4827   ADD_KEYDEF(_("ctrl-left-arrow"), _("move timeline cursor left 1 second"));
4828   ADD_KEYDEF(_("ctrl-right-arrow"), _("move timeline cursor right 1 second"));
4829   ADD_KEYDEF(_("shift-left-arrow"), _("move timeline cursor left 1 frame"));
4830   ADD_KEYDEF(_("shift-right-arrow"), _("move timeline cursor right 1 frame"));
4831   ADD_KEYDEF(_("ctrl-up-arrow"), _("move current track up"));
4832   ADD_KEYDEF(_("ctrl-down-arrow"), _("move current track down"));
4833   ADD_KEYDEF(_("ctrl-page-up"), _("select previous clip"));
4834   ADD_KEYDEF(_("ctrl-page-down"), _("select next clip"));
4835   ADD_KEYDEF(_("ctrl-space"), _("select/deselect current track"));
4836   ADD_KEYDEF(_("ctrl-plus"), _("zoom in"));
4837   ADD_KEYDEF(_("ctrl-minus"), _("zoom out"));
4838   ADD_KEYDEF("m", _("make a mark on the timeline (during playback)"));
4839   ADD_KEYDEF("w", _("rewind to play start."));
4840   ADD_KEYDEF("", "");
4841   ADD_KEYDEF("", _("For other keys, see the menus.\n"));
4842   ADD_KEYDEF("", "");
4843 }
4844 
4845 
autolives_pre_dialog(void)4846 autolives_window *autolives_pre_dialog(void) {
4847   // dialog for autolives activation
4848   // options: trigger: auto, time
4849   //                   omc - user1
4850 
4851   // TODO: add port numbers, add change types and probabilities.
4852   autolives_window *alwindow;
4853 
4854   LiVESWidget *trigframe;
4855   LiVESWidget *dialog_vbox;
4856   LiVESWidget *label;
4857   LiVESWidget *vbox;
4858   LiVESWidget *hbox;
4859   LiVESWidget *radiobutton;
4860 
4861   LiVESSList *radiobutton1_group = NULL;
4862   LiVESSList *radiobutton2_group = NULL;
4863 
4864   char *tmp, *tmp2;
4865 
4866   alwindow = (autolives_window *)lives_malloc(sizeof(autolives_window));
4867 
4868   alwindow->dialog = lives_standard_dialog_new(_("Autolives Options"), TRUE, DEF_DIALOG_WIDTH, DEF_DIALOG_HEIGHT);
4869 
4870   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(alwindow->dialog));
4871 
4872   trigframe = lives_standard_frame_new(_("Trigger"), 0., FALSE);
4873 
4874   lives_box_pack_start(LIVES_BOX(dialog_vbox), trigframe, FALSE, FALSE, widget_opts.packing_height);
4875 
4876   vbox = lives_vbox_new(FALSE, 0);
4877   lives_container_set_border_width(LIVES_CONTAINER(vbox), widget_opts.border_width);
4878   lives_container_add(LIVES_CONTAINER(trigframe), vbox);
4879 
4880   hbox = lives_hbox_new(FALSE, widget_opts.packing_width);
4881   lives_box_pack_start(LIVES_BOX(vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
4882   alwindow->atrigger_button = lives_standard_radio_button_new((tmp = (_("Timed:"))),
4883                               &radiobutton1_group, LIVES_BOX(hbox),
4884                               (tmp2 = (_("Trigger a change based on time"))));
4885 
4886   lives_free(tmp); lives_free(tmp2);
4887 
4888   alwindow->atrigger_spin = lives_standard_spin_button_new(_("change time (seconds)"), 1., 1., 1800.,
4889                             1., 10., 0, LIVES_BOX(hbox), NULL);
4890 
4891   hbox = lives_hbox_new(FALSE, widget_opts.packing_width);
4892   lives_box_pack_start(LIVES_BOX(vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
4893   radiobutton = lives_standard_radio_button_new((tmp = (_("OMC"))),
4894                 &radiobutton1_group, LIVES_BOX(hbox),
4895                 (tmp2 = (_("Trigger a change based on receiving an OSC message"))));
4896 
4897   lives_free(tmp); lives_free(tmp2);
4898 
4899   if (has_devicemap(OSC_NOTIFY)) {
4900     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton), TRUE);
4901   }
4902 
4903   vbox = lives_vbox_new(FALSE, 0);
4904   lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox, TRUE, FALSE, widget_opts.packing_height * 2.);
4905 
4906   hbox = lives_hbox_new(FALSE, 0);
4907   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
4908 
4909   label = lives_standard_label_new(_("Playback start:"));
4910   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, TRUE, 0);
4911 
4912   add_fill_to_box(LIVES_BOX(hbox));
4913 
4914   hbox = lives_hbox_new(FALSE, widget_opts.packing_width);
4915   lives_box_pack_start(LIVES_BOX(vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
4916   alwindow->apb_button = lives_standard_radio_button_new((tmp = (_("Automatic"))),
4917                          &radiobutton2_group, LIVES_BOX(hbox),
4918                          (tmp2 = (_("Start playback automatically"))));
4919 
4920   lives_free(tmp); lives_free(tmp2);
4921 
4922   radiobutton = lives_standard_radio_button_new((tmp = (_("Manual"))),
4923                 &radiobutton2_group, LIVES_BOX(hbox),
4924                 (tmp2 = (_("Wait for the user to start playback"))));
4925 
4926   lives_free(tmp); lives_free(tmp2);
4927 
4928   hbox = lives_hbox_new(FALSE, widget_opts.packing_width);
4929   lives_box_pack_start(LIVES_BOX(vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 2);
4930 
4931   alwindow->mute_button = lives_standard_check_button_new
4932                           ((tmp = (_("Mute internal audio during playback"))), FALSE, LIVES_BOX(hbox),
4933                            (tmp2 = (_("Mute the audio in LiVES during playback by setting the audio source to external."))));
4934 
4935   lives_free(tmp); lives_free(tmp2);
4936 
4937   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(alwindow->mute_button), TRUE);
4938 
4939   add_hsep_to_box(LIVES_BOX(dialog_vbox));
4940 
4941   hbox = lives_hbox_new(FALSE, 0);
4942   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
4943 
4944   alwindow->debug_button = lives_standard_check_button_new
4945                            ((tmp = (_("Debug mode"))), FALSE, LIVES_BOX(hbox),
4946                             (tmp2 = (_("Show debug output on stderr."))));
4947 
4948   lives_free(tmp); lives_free(tmp2);
4949 
4950   lives_widget_show_all(alwindow->dialog);
4951   return alwindow;
4952 }
4953 
4954 
special_cleanup_cb(LiVESWidget * widget,void * userdata)4955 static boolean special_cleanup_cb(LiVESWidget * widget, void *userdata) {
4956   // need to call special_cleanup(TRUE) before destroying the toplevel if you want to prompt
4957   // for filewrite overwrites
4958   special_cleanup(FALSE);
4959   return FALSE;
4960 }
4961 
4962 
add_aspect_ratio_button(LiVESSpinButton * sp_width,LiVESSpinButton * sp_height,LiVESBox * box)4963 const lives_special_aspect_t *add_aspect_ratio_button(LiVESSpinButton * sp_width, LiVESSpinButton * sp_height, LiVESBox * box) {
4964   static lives_param_t aspect_width, aspect_height;
4965 
4966   init_special();
4967 
4968   aspect_width.widgets[0] = (LiVESWidget *)sp_width;
4969   aspect_height.widgets[0] = (LiVESWidget *)sp_height;
4970 
4971   set_aspect_ratio_widgets(&aspect_width, &aspect_height);
4972 
4973   check_for_special(NULL, &aspect_width, box);
4974   check_for_special(NULL, &aspect_height, box);
4975 
4976   lives_signal_sync_connect(LIVES_GUI_OBJECT(sp_width), LIVES_WIDGET_DESTROY_SIGNAL,
4977                             LIVES_GUI_CALLBACK(special_cleanup_cb), NULL);
4978 
4979   return paramspecial_get_aspect();
4980 }
4981 
4982 
add_list_expander(LiVESBox * box,const char * title,int width,int height,LiVESList * xlist)4983 LiVESWidget *add_list_expander(LiVESBox * box, const char *title, int width, int height, LiVESList * xlist) {
4984   // add widget to preview affected layouts
4985 
4986   LiVESWidget *expander;
4987   LiVESWidget *textview = lives_text_view_new();
4988   LiVESTextBuffer *textbuffer = lives_text_view_get_buffer(LIVES_TEXT_VIEW(textview));
4989 
4990   LiVESWidget *scrolledwindow =
4991     lives_standard_scrolled_window_new(width, height, LIVES_WIDGET(textview));
4992 
4993   lives_text_view_set_editable(LIVES_TEXT_VIEW(textview), FALSE);
4994 
4995   lives_widget_set_size_request(scrolledwindow, width, height);
4996 
4997   expander = lives_standard_expander_new(title, LIVES_BOX(box), scrolledwindow);
4998 
4999   if (palette->style & STYLE_1) {
5000     LiVESWidget *label = lives_expander_get_label_widget(LIVES_EXPANDER(expander));
5001     lives_widget_set_fg_color(label, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
5002     lives_widget_set_fg_color(label, LIVES_WIDGET_STATE_PRELIGHT, &palette->normal_fore);
5003     lives_widget_set_fg_color(expander, LIVES_WIDGET_STATE_PRELIGHT, &palette->normal_fore);
5004     lives_widget_set_bg_color(expander, LIVES_WIDGET_STATE_PRELIGHT, &palette->normal_back);
5005 
5006     lives_widget_set_base_color(textview, LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
5007     lives_widget_set_text_color(textview, LIVES_WIDGET_STATE_NORMAL, &palette->info_text);
5008     lives_widget_set_base_color(scrolledwindow, LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
5009     lives_widget_set_text_color(scrolledwindow, LIVES_WIDGET_STATE_NORMAL, &palette->info_text);
5010   }
5011 
5012   lives_text_buffer_insert_at_cursor(textbuffer, "\n", strlen("\n"));
5013 
5014   for (; xlist; xlist = xlist->next) {
5015     lives_text_buffer_insert_at_cursor(textbuffer, (const char *)xlist->data, strlen((char *)xlist->data));
5016     lives_text_buffer_insert_at_cursor(textbuffer, "\n", strlen("\n"));
5017   }
5018   return expander;
5019 }
5020 
5021 
5022 #ifdef ALLOW_NONFREE_CODECS
on_freedom_toggled(LiVESToggleButton * togglebutton,livespointer user_data)5023 static void on_freedom_toggled(LiVESToggleButton * togglebutton, livespointer user_data) {
5024   LiVESWidget *label = (LiVESWidget *)user_data;
5025   if (!lives_toggle_button_get_active(togglebutton)) lives_label_set_text(LIVES_LABEL(label), "." LIVES_FILE_EXT_WEBM);
5026   else lives_label_set_text(LIVES_LABEL(label), "." LIVES_FILE_EXT_MP4);
5027 }
5028 #endif
5029 
5030 static LiVESWidget *spinbutton_width;
5031 static LiVESWidget *spinbutton_height;
5032 static const lives_special_aspect_t *aspect;
5033 
utsense(LiVESToggleButton * togglebutton,livespointer user_data)5034 static void utsense(LiVESToggleButton * togglebutton, livespointer user_data) {
5035   boolean sensitive = (boolean)LIVES_POINTER_TO_INT(user_data);
5036   if (!lives_toggle_button_get_active(togglebutton)) return;
5037   lives_widget_set_sensitive(spinbutton_width, sensitive);
5038   lives_widget_set_sensitive(spinbutton_height, sensitive);
5039   if (aspect) lives_widget_set_sensitive(aspect->lockbutton, sensitive);
5040 }
5041 
dl_url_changed(LiVESWidget * urlw,livespointer user_data)5042 static void dl_url_changed(LiVESWidget * urlw, livespointer user_data) {
5043   LiVESWidget *namew = (LiVESWidget *)user_data;
5044   static size_t oldlen = 0;
5045   size_t ulen = lives_strlen(lives_entry_get_text(LIVES_ENTRY(urlw)));
5046   if (!(*(lives_entry_get_text(LIVES_ENTRY(namew))))) {
5047     if (ulen > oldlen + 1) lives_widget_grab_focus(namew);
5048   }
5049   oldlen = ulen;
5050 }
5051 
5052 
on_utupinfo_clicked(LiVESWidget * b,livespointer data)5053 static void on_utupinfo_clicked(LiVESWidget * b, livespointer data) {
5054   do_info_dialogf(_("LiVES will only update %s if you have a local user copy installed.\n"
5055                     "Otherwise you may need to update it manually when prompted\n\n"
5056                     "Checking the button for the first time will cause the program to be copied\n"
5057                     "to your home directory.\n"
5058                     "After this it can be updated without needing root privileges.\n"),
5059                   EXEC_YOUTUBE_DL);
5060 }
5061 
5062 // prompt for the following:
5063 // - URL
5064 // save dir
5065 // format selection (free / nonfree)
5066 // filename
5067 // approx file size
5068 // update youtube-dl
5069 // advanced :: audio selection / save subs / sub language [TODO]
5070 
run_youtube_dialog(lives_remote_clip_request_t * req)5071 lives_remote_clip_request_t *run_youtube_dialog(lives_remote_clip_request_t *req) {
5072   LiVESWidget *dialog_vbox;
5073   LiVESWidget *label;
5074   LiVESWidget *ext_label;
5075   LiVESWidget *hbox;
5076   LiVESWidget *dialog;
5077   LiVESWidget *url_entry;
5078   LiVESWidget *name_entry;
5079   LiVESWidget *dir_entry;
5080   LiVESWidget *checkbutton_update;
5081   LiVESWidget *cb_debug = NULL;
5082 #ifdef ALLOW_NONFREE_CODECS
5083   LiVESWidget *radiobutton_free;
5084   LiVESWidget *radiobutton_nonfree;
5085 #endif
5086   LiVESWidget *radiobutton_approx;
5087   LiVESWidget *radiobutton_atleast;
5088   LiVESWidget *radiobutton_atmost;
5089   LiVESWidget *radiobutton_smallest;
5090   LiVESWidget *radiobutton_largest;
5091   LiVESWidget *radiobutton_choose;
5092   LiVESWidget *button;
5093 
5094   double width_step = 4.;
5095   double height_step = 4.;
5096 
5097   char *fname;
5098 
5099 #ifdef ALLOW_NONFREE_CODECS
5100   LiVESSList *radiobutton_group = NULL;
5101 #endif
5102   LiVESSList *radiobutton_group2 = NULL;
5103 
5104   char *title, *tmp, *tmp2, *msg;
5105   char *dfile = NULL, *url = NULL;
5106 
5107   char dirname[PATH_MAX];
5108 #ifdef YTDL_URL
5109   uint64_t gflags = 0;
5110 #endif
5111 
5112   LiVESResponseType response;
5113   boolean only_free = TRUE;
5114   boolean debug = FALSE;
5115   static boolean firsttime = TRUE;
5116 
5117   if (!req || !req->do_update) {
5118 #ifdef YTDL_URL
5119     /// thanks RIAA...
5120     gflags |= INSTALL_CANLOCAL;
5121 #endif
5122     if (!check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL) &&
5123         !check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC)
5124        ) {
5125       if (!do_please_install_either(EXEC_YOUTUBE_DL, EXEC_YOUTUBE_DLC)) {
5126         capable->has_youtube_dl = capable->has_youtube_dlc = UNCHECKED;
5127         return NULL;
5128       }
5129     }
5130     if (capable->has_youtube_dl != LOCAL) {
5131       /// local version not found, so try first with system version
5132       firsttime = FALSE;
5133     }
5134   } else if (firsttime) {
5135     if (!check_for_executable(&capable->has_pip, EXEC_PIP)) {
5136       /// requirement is missing, if the user does set it checked, we will warn
5137       firsttime = FALSE;
5138     }
5139   }
5140 
5141 #ifdef ALLOW_NONFREE_CODECS
5142   if (req) only_free = !req->allownf;
5143 #endif
5144 
5145   if (req) debug = req->debug;
5146 
5147   title = (_("Open Online Clip"));
5148 
5149   dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
5150   lives_signal_handlers_disconnect_by_func(dialog, LIVES_GUI_CALLBACK(return_true), NULL);
5151 
5152   lives_free(title);
5153 
5154   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
5155 
5156   widget_opts.justify = LIVES_JUSTIFY_CENTER;
5157   msg = lives_strdup_printf(_("To open a clip from Youtube or another video site, LiVES will first download it with %s.\n"),
5158                             EXEC_YOUTUBE_DL);
5159   label = lives_standard_label_new(msg);
5160   lives_free(msg);
5161 
5162   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, 0);
5163 
5164   hbox = lives_hbox_new(FALSE, 0);
5165   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height * 2);
5166 
5167   add_spring_to_box(LIVES_BOX(hbox), 0);
5168 
5169   msg = lives_big_and_bold(_("<--- Install or Update local copy of %s ?"), EXEC_YOUTUBE_DL);
5170   widget_opts.use_markup = TRUE;
5171   checkbutton_update = lives_standard_check_button_new(msg, firsttime || (req && req->do_update),
5172                        LIVES_BOX(hbox),
5173                        H_("If checked then LiVES will attempt to update\n"
5174                           "it to the most recent version\n"
5175                           "before attempting the download."));
5176   widget_opts.use_markup = FALSE;
5177   lives_free(msg);
5178 
5179   button = lives_standard_button_new_from_stock_full(LIVES_STOCK_DIALOG_INFO, _("_Info"),
5180            DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT, LIVES_BOX(hbox), TRUE, NULL);
5181 
5182   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
5183                             LIVES_GUI_CALLBACK(on_utupinfo_clicked), NULL);
5184 
5185   add_spring_to_box(LIVES_BOX(hbox), 0);
5186 
5187   label = lives_standard_label_new(_("Enter the URL of the clip below.\n"
5188                                      "E.g: http://www.youtube.com/watch?v=WCR6f6WzjP8"));
5189   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
5190 
5191   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, 0);
5192 
5193   hbox = lives_hbox_new(FALSE, 0);
5194   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
5195 
5196   url_entry = lives_standard_entry_new(_("Clip URL : "), req ? req->URI : "",
5197                                        LONG_ENTRY_WIDTH, URL_MAX, LIVES_BOX(hbox), NULL);
5198 
5199   hbox = lives_hbox_new(FALSE, 0);
5200   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height);
5201 
5202   if (only_free)
5203     ext_label = lives_standard_label_new("." LIVES_FILE_EXT_WEBM);
5204   else
5205     ext_label = lives_standard_label_new("." LIVES_FILE_EXT_MP4);
5206 
5207 #ifdef ALLOW_NONFREE_CODECS
5208   label = lives_standard_label_new(_("Format selection:"));
5209 
5210   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
5211 
5212   radiobutton_free =
5213     lives_standard_radio_button_new((tmp = (_("_Free (eg. vp9 / opus / webm)"))), &radiobutton_group, LIVES_BOX(hbox),
5214                                     (tmp2 = (_("Download clip using Free codecs and support the community"))));
5215 
5216   lives_free(tmp); lives_free(tmp2);
5217 
5218   add_fill_to_box(LIVES_BOX(hbox));
5219 
5220 #endif
5221   name_entry = lives_standard_entry_new(_("_File Name : "), req ? req->fname : "",
5222                                         SHORT_ENTRY_WIDTH, PATH_MAX, LIVES_BOX(hbox), NULL);
5223 
5224   lives_box_pack_start(LIVES_BOX(hbox), ext_label, FALSE, FALSE, 0);
5225   lives_signal_sync_connect(LIVES_GUI_OBJECT(url_entry), LIVES_WIDGET_CHANGED_SIGNAL,
5226                             LIVES_GUI_CALLBACK(dl_url_changed), name_entry);
5227 
5228 #ifdef ALLOW_NONFREE_CODECS
5229   //
5230   hbox = lives_hbox_new(FALSE, 0);
5231 
5232   lives_widget_show_all(dialog);
5233   lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5234   lives_box_pack_start(LIVES_BOX(dialog_vbox), align_horizontal_with(hbox, radiobutton_free),
5235                        TRUE, FALSE, widget_opts.packing_height);
5236 
5237   radiobutton_nonfree = lives_standard_radio_button_new((tmp = (_("_Non-free (eg. h264 / aac / mp4)"))),
5238                         &radiobutton_group,  LIVES_BOX(hbox),
5239                         (tmp2 = (_("Download clip using non-free codecs and support commercial interests"))));
5240 
5241   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton_nonfree), !only_free);
5242 
5243   lives_free(tmp); lives_free(tmp2);
5244 
5245   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_nonfree), LIVES_WIDGET_TOGGLED_SIGNAL,
5246                             LIVES_GUI_CALLBACK(on_freedom_toggled), (livespointer)ext_label);
5247 
5248 #endif
5249 
5250   toggle_toggles_var(LIVES_TOGGLE_BUTTON(radiobutton_free), &only_free, FALSE);
5251 
5252   hbox = lives_hbox_new(FALSE, 0);
5253   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height * 3);
5254 
5255   dir_entry = lives_standard_direntry_new(_("_Directory to save to: "),
5256                                           req ? req->save_dir : mainw->vid_dl_dir,
5257                                           LONG_ENTRY_WIDTH, PATH_MAX, LIVES_BOX(hbox), NULL);
5258 
5259   if (prefs->show_dev_opts) {
5260     cb_debug = lives_standard_check_button_new("Debug mode", debug,
5261                LIVES_BOX(hbox), NULL);
5262     hbox = lives_hbox_new(FALSE, 0);
5263     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height * 3);
5264     toggle_toggles_var(LIVES_TOGGLE_BUTTON(cb_debug), &debug, FALSE);
5265   }
5266 
5267   add_hsep_to_box(LIVES_BOX(dialog_vbox));
5268 
5269   hbox = lives_hbox_new(FALSE, 0);
5270   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height);
5271 
5272   label = lives_standard_label_new(_("Desired frame size:"));
5273   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
5274 
5275   hbox = lives_hbox_new(FALSE, 0);
5276   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height);
5277 
5278   radiobutton_approx = lives_standard_radio_button_new((tmp = (_("- Approximately:"))),
5279                        &radiobutton_group2, LIVES_BOX(hbox),
5280                        (tmp2 = (_("Download the closest to this size"))));
5281 
5282   lives_free(tmp); lives_free(tmp2);
5283 
5284   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_approx), LIVES_WIDGET_TOGGLED_SIGNAL,
5285                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(TRUE));
5286 
5287   radiobutton_atleast = lives_standard_radio_button_new((tmp = (_("- At _least"))), &radiobutton_group2,
5288                         LIVES_BOX(hbox),
5289                         (tmp2 = (_("Frame size should be at least this size"))));
5290   lives_free(tmp); lives_free(tmp2);
5291 
5292   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_atleast), LIVES_WIDGET_TOGGLED_SIGNAL,
5293                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(TRUE));
5294 
5295   radiobutton_atmost = lives_standard_radio_button_new((tmp = (_("- At _most:"))), &radiobutton_group2,
5296                        LIVES_BOX(hbox),
5297                        (tmp2 = (_("Frame size should be at most this size"))));
5298   lives_free(tmp); lives_free(tmp2);
5299 
5300   add_param_label_to_box(LIVES_BOX(hbox), FALSE, "------>");
5301 
5302   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_atmost), LIVES_WIDGET_TOGGLED_SIGNAL,
5303                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(TRUE));
5304 
5305   add_fill_to_box(LIVES_BOX(hbox));
5306 
5307   spinbutton_width = lives_standard_spin_button_new(_("_Width"),
5308                      CURRENT_CLIP_HAS_VIDEO ? cfile->hsize : DEF_GEN_WIDTH,
5309                      width_step, 100000., width_step, width_step, 0, LIVES_BOX(hbox), NULL);
5310 
5311   lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(spinbutton_width), width_step);
5312   lives_spin_button_update(LIVES_SPIN_BUTTON(spinbutton_width));
5313 
5314   spinbutton_height = lives_standard_spin_button_new(_("X\t_Height"),
5315                       CURRENT_CLIP_HAS_VIDEO ? cfile->vsize : DEF_GEN_HEIGHT,
5316                       height_step, 100000., height_step, height_step, 0, LIVES_BOX(hbox), NULL);
5317 
5318   lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(spinbutton_height), height_step);
5319   lives_spin_button_update(LIVES_SPIN_BUTTON(spinbutton_height));
5320 
5321   label = lives_standard_label_new(_("\tpixels"));
5322   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, 0);
5323 
5324   // add "aspectratio" widget
5325   if (CURRENT_CLIP_HAS_VIDEO) {
5326     aspect = add_aspect_ratio_button(LIVES_SPIN_BUTTON(spinbutton_width),
5327                                      LIVES_SPIN_BUTTON(spinbutton_height), LIVES_BOX(hbox));
5328   } else aspect = NULL;
5329 
5330   hbox = lives_hbox_new(FALSE, 0);
5331   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height);
5332 
5333   label = lives_standard_label_new(_(" or:"));
5334   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
5335 
5336   hbox = lives_hbox_new(FALSE, 0);
5337   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height);
5338 
5339   radiobutton_smallest = lives_standard_radio_button_new((tmp = (_("- The _smallest"))),
5340                          &radiobutton_group2, LIVES_BOX(hbox),
5341                          (tmp2 = (_("Download the lowest resolution available"))));
5342 
5343   lives_free(tmp); lives_free(tmp2);
5344 
5345   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_smallest), LIVES_WIDGET_TOGGLED_SIGNAL,
5346                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(FALSE));
5347 
5348   radiobutton_largest = lives_standard_radio_button_new((tmp = (_("- The _largest"))),
5349                         &radiobutton_group2, LIVES_BOX(hbox),
5350                         (tmp2 = (_("Download the highest resolution available"))));
5351 
5352   lives_free(tmp); lives_free(tmp2);
5353 
5354   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_largest), LIVES_WIDGET_TOGGLED_SIGNAL,
5355                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(FALSE));
5356 
5357   add_fill_to_box(LIVES_BOX(hbox));
5358   add_fill_to_box(LIVES_BOX(hbox));
5359 
5360   radiobutton_choose = lives_standard_radio_button_new((tmp = (_("- Let me choose..."))),
5361                        &radiobutton_group2, LIVES_BOX(hbox),
5362                        (tmp2 = (_("Choose the resolution from a list (opens in new window)"))));
5363 
5364   lives_free(tmp); lives_free(tmp2);
5365 
5366   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton_choose), LIVES_WIDGET_TOGGLED_SIGNAL,
5367                             LIVES_GUI_CALLBACK(utsense), LIVES_INT_TO_POINTER(FALSE));
5368 
5369   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton_choose), TRUE);
5370 
5371   ///////
5372 
5373   hbox = lives_hbox_new(FALSE, 0);
5374   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, FALSE, widget_opts.packing_height * 2);
5375 
5376   add_spring_to_box(LIVES_BOX(hbox), 0);
5377   lives_standard_expander_new(_("_Other options (e.g audio, subtitles)..."), LIVES_BOX(hbox), NULL);
5378   add_spring_to_box(LIVES_BOX(hbox), 0);
5379 
5380   lives_widget_grab_focus(url_entry);
5381 
5382   // TODO - add other options
5383 
5384   //lives_widget_show_all(dialog);
5385 
5386   while (1) {
5387     response = lives_dialog_run(LIVES_DIALOG(dialog));
5388     if (response == LIVES_RESPONSE_CANCEL) {
5389       mainw->cancelled = CANCEL_USER;
5390       return NULL;
5391     }
5392 
5393     ///////
5394 
5395     if (!*lives_entry_get_text(LIVES_ENTRY(name_entry))) {
5396       do_error_dialog(_("Please enter the name of the file to save the downloaded clip as.\n"));
5397       continue;
5398     }
5399 
5400     url = lives_strdup(lives_entry_get_text(LIVES_ENTRY(url_entry)));
5401 
5402     if (!(*url)) {
5403       lives_free(url);
5404       do_error_dialog(_("Please enter a valid URL for the download.\n"));
5405       continue;
5406     }
5407 
5408     fname = ensure_extension(lives_entry_get_text(LIVES_ENTRY(name_entry)), only_free ? LIVES_FILE_EXT_WEBM
5409                              : LIVES_FILE_EXT_MP4);
5410     lives_snprintf(dirname, PATH_MAX, "%s", lives_entry_get_text(LIVES_ENTRY(dir_entry)));
5411     ensure_isdir(dirname);
5412     dfile = lives_build_filename(dirname, fname, NULL);
5413     lives_free(fname);
5414     if (!check_file(dfile, TRUE)) {
5415       lives_free(dfile);
5416       lives_free(url);
5417       continue;
5418     }
5419     break;
5420   }
5421 
5422   lives_snprintf(mainw->vid_dl_dir, PATH_MAX, "%s", dirname);
5423 
5424   if (!req) {
5425     req = (lives_remote_clip_request_t *)lives_calloc(1, sizeof(lives_remote_clip_request_t));
5426     if (!req) {
5427       lives_widget_destroy(dialog);
5428       lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5429       lives_free(url); lives_free(dfile);
5430       LIVES_ERROR("Could not alloc memory for remote clip request");
5431       mainw->error = TRUE;
5432       return NULL;
5433     }
5434     req->allownf = !only_free;
5435   }
5436 
5437   req->debug = debug;
5438 
5439   mainw->error = FALSE;
5440   d_print(_("Downloading %s to %s..."), url, dfile);
5441   lives_free(dfile);
5442 
5443   lives_snprintf(req->URI, 8192, "%s", url);
5444   lives_free(url);
5445   lives_snprintf(req->save_dir, PATH_MAX, "%s", dirname);
5446   lives_snprintf(req->fname, PATH_MAX, "%s", lives_entry_get_text(LIVES_ENTRY(name_entry)));
5447 #ifdef ALLOW_NONFREE_CODECS
5448   if (!req->allownf)
5449     lives_snprintf(req->format, 256, "%s", LIVES_FILE_EXT_WEBM);
5450   else
5451     lives_snprintf(req->format, 256, "%s", LIVES_FILE_EXT_MP4);
5452 #else
5453   lives_snprintf(req->format, 256, "%s", LIVES_FILE_EXT_WEBM);
5454 #endif
5455   req->desired_width = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton_width));
5456   req->desired_height = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton_height));
5457   req->desired_fps = 0.;
5458   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_approx)))
5459     req->matchsize = LIVES_MATCH_NEAREST;
5460   else if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_atleast)))
5461     req->matchsize = LIVES_MATCH_AT_LEAST;
5462   else if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_atmost)))
5463     req->matchsize = LIVES_MATCH_AT_MOST;
5464   else if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_smallest)))
5465     req->matchsize = LIVES_MATCH_HIGHEST;
5466   else if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_largest)))
5467     req->matchsize = LIVES_MATCH_LOWEST;
5468   else if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton_choose)))
5469     req->matchsize = LIVES_MATCH_CHOICE;
5470   if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(checkbutton_update))) req->do_update = FALSE;
5471   else {
5472     req->do_update = TRUE;
5473   }
5474   *req->vidchoice = 0;
5475   *req->audchoice = 0;
5476 
5477   lives_widget_destroy(dialog);
5478   lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5479   firsttime = FALSE;
5480   return req;
5481 }
5482 
5483 
on_ebox_click(LiVESWidget * widget,LiVESXEventButton * event,livespointer user_data)5484 static boolean on_ebox_click(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
5485   // want to get doubleclick and then exit somehow
5486   int val = LIVES_POINTER_TO_INT(user_data);
5487   if (event->type != LIVES_BUTTON_PRESS) {
5488     lives_dialog_response(LIVES_DIALOG(lives_widget_get_toplevel(widget)), val);
5489     lives_widget_destroy(lives_widget_get_toplevel(LIVES_WIDGET(widget)));
5490   }
5491   return TRUE;
5492 }
5493 
5494 
youtube_select_format(lives_remote_clip_request_t * req)5495 boolean youtube_select_format(lives_remote_clip_request_t *req) {
5496   // need to set req->vidchoice
5497   int numlines, npieces;
5498   int width, height;
5499   int i, j, dbw, pdone;
5500   int scrw = GUI_SCREEN_WIDTH;
5501   int scrh = GUI_SCREEN_HEIGHT;
5502   int row = 1;
5503   int response;
5504 
5505   size_t slen;
5506 
5507   char **lines, **pieces;
5508   char *title, *txt;
5509 
5510   char *notes;
5511 
5512   LiVESWidget *dialog, *dialog_vbox, *scrollw, *table;
5513   LiVESWidget *label, *eventbox, *cancelbutton;
5514   LiVESWidget *abox;
5515 
5516   LiVESList *allids = NULL;
5517 
5518   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
5519 
5520   if (lives_strlen(mainw->msg) < 10) return FALSE;
5521   numlines = get_token_count(mainw->msg, '|');
5522   if (numlines < 2) return FALSE;
5523   lines = lives_strsplit(mainw->msg, "|", numlines);
5524   if (strcmp(lines[0], "completed")) {
5525     lives_strfreev(lines);
5526     return FALSE;
5527   }
5528 
5529   // create the dialog with a scrolledwindow
5530   width = scrw - SCR_WIDTH_SAFETY;
5531   height = (scrh - SCR_HEIGHT_SAFETY) / 2;
5532 
5533   title = (_("Select Video Format to Download"));
5534   dialog = lives_standard_dialog_new(title, FALSE, 8, 8);
5535   lives_free(title);
5536 
5537   abox = lives_dialog_get_action_area(LIVES_DIALOG(dialog));
5538   if (LIVES_IS_BOX(abox)) {
5539     label = lives_standard_label_new(_("Double click on a format to load it, or click Cancel to exit."));
5540     lives_box_pack_start(LIVES_BOX(abox), label, FALSE, TRUE, widget_opts.border_width);
5541 
5542     add_fill_to_box(LIVES_BOX(abox));
5543   }
5544 
5545   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
5546                  LIVES_RESPONSE_CANCEL);
5547 
5548   lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
5549                             LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
5550 
5551   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
5552                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
5553 
5554   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
5555 
5556   table = lives_table_new(numlines + 1, 5, FALSE);
5557   lives_table_set_row_spacings(LIVES_TABLE(table), widget_opts.packing_height * 2);
5558 
5559   dbw = widget_opts.border_width;
5560 
5561   // need to set a large enough default here
5562   scrollw = lives_standard_scrolled_window_new(width * .8, height * 1., table);
5563   widget_opts.border_width = dbw;
5564 
5565   lives_box_pack_start(LIVES_BOX(dialog_vbox), scrollw, FALSE, TRUE, 0);
5566   lives_container_set_border_width(LIVES_CONTAINER(table), 0);
5567 
5568   notes = lives_strdup("");
5569 
5570   // set the column headings
5571   label = lives_standard_label_new(_("ID"));
5572   lives_table_attach(LIVES_TABLE(table), label, 0, 1, 0, 1,
5573                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5574                      (LiVESAttachOptions)(0), 0, 0);
5575   lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5576   lives_widget_set_valign(label, LIVES_ALIGN_END);
5577 
5578   label = lives_standard_label_new(_("Format"));
5579   lives_table_attach(LIVES_TABLE(table), label, 1, 2, 0, 1,
5580                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5581                      (LiVESAttachOptions)(0), 0, 0);
5582   lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5583   lives_widget_set_valign(label, LIVES_ALIGN_END);
5584 
5585   label = lives_standard_label_new(_("Resolution"));
5586   lives_table_attach(LIVES_TABLE(table), label, 2, 3, 0, 1,
5587                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5588                      (LiVESAttachOptions)(0), 0, 0);
5589   lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5590   lives_widget_set_valign(label, LIVES_ALIGN_END);
5591 
5592   label = lives_standard_label_new(_("Notes"));
5593   lives_table_attach(LIVES_TABLE(table), label, 3, 4, 0, 1,
5594                      (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5595                      (LiVESAttachOptions)(0), 0, 0);
5596   lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5597   lives_widget_set_valign(label, LIVES_ALIGN_END);
5598 
5599 
5600   for (i = 1; i < numlines; i++) {
5601     npieces = get_token_count(lines[i], ' ');
5602     pieces = lives_strsplit(lines[i], " ", npieces);
5603     pdone = 0;
5604 
5605     for (j = 0; j < npieces; j++) {
5606       if (pdone < 3 && !*pieces[j]) continue;
5607 
5608       if (pdone == 0) {
5609         // id no
5610         txt = lives_strdup_printf("\n%s\n", pieces[j]);
5611         label = lives_standard_label_new(txt);
5612         lives_free(txt);
5613         lives_widget_apply_theme3(label, LIVES_WIDGET_STATE_NORMAL);
5614         eventbox = lives_event_box_new();
5615         lives_container_add(LIVES_CONTAINER(eventbox), label);
5616         lives_event_box_set_above_child(LIVES_EVENT_BOX(eventbox), TRUE);
5617         lives_signal_sync_connect(LIVES_GUI_OBJECT(eventbox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
5618                                   LIVES_GUI_CALLBACK(on_ebox_click),
5619                                   LIVES_INT_TO_POINTER(row - 1));
5620         lives_table_attach(LIVES_TABLE(table), eventbox, 0, 1, row, row + 1,
5621                            (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5622                            (LiVESAttachOptions)(0), 0, 0);
5623         lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5624         allids = lives_list_append(allids, lives_strdup(pieces[j]));
5625         pdone = 1;
5626         continue;
5627       }
5628 
5629       if (pdone == 1) {
5630         // format
5631         txt = lives_strdup_printf("\n%s\n", pieces[j]);
5632         label = lives_standard_label_new(txt);
5633         lives_free(txt);
5634         lives_widget_apply_theme3(label, LIVES_WIDGET_STATE_NORMAL);
5635         eventbox = lives_event_box_new();
5636         lives_container_add(LIVES_CONTAINER(eventbox), label);
5637         lives_event_box_set_above_child(LIVES_EVENT_BOX(eventbox), TRUE);
5638         lives_signal_sync_connect(LIVES_GUI_OBJECT(eventbox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
5639                                   LIVES_GUI_CALLBACK(on_ebox_click),
5640                                   LIVES_INT_TO_POINTER(row - 1));
5641         lives_table_attach(LIVES_TABLE(table), eventbox, 1, 2, row, row + 1,
5642                            (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5643                            (LiVESAttachOptions)(0), 0, 0);
5644         lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5645         pdone = 2;
5646         continue;
5647       }
5648 
5649       if (pdone == 2) {
5650         // res
5651         txt = lives_strdup_printf("\n%s\n", pieces[j]);
5652         label = lives_standard_label_new(txt);
5653         lives_free(txt);
5654         lives_widget_apply_theme3(label, LIVES_WIDGET_STATE_NORMAL);
5655         eventbox = lives_event_box_new();
5656         lives_container_add(LIVES_CONTAINER(eventbox), label);
5657         lives_event_box_set_above_child(LIVES_EVENT_BOX(eventbox), TRUE);
5658         lives_signal_sync_connect(LIVES_GUI_OBJECT(eventbox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
5659                                   LIVES_GUI_CALLBACK(on_ebox_click),
5660                                   LIVES_INT_TO_POINTER(row - 1));
5661         lives_table_attach(LIVES_TABLE(table), eventbox, 2, 3, row, row + 1,
5662                            (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5663                            (LiVESAttachOptions)(0), 0, 0);
5664         lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
5665         pdone = 3;
5666         continue;
5667       }
5668       notes = lives_strdup_printf("%s %s", notes, pieces[j]);
5669     }
5670 
5671     lives_strfreev(pieces);
5672 
5673     slen = lives_strlen(notes);
5674     // strip trailing newline
5675     if (slen > 0 && notes[slen - 1] == '\n') notes[slen - 1] = 0;
5676 
5677     txt = lives_strdup_printf("\n%s\n", notes);
5678     label = lives_standard_label_new(txt);
5679     lives_free(txt);
5680     lives_widget_apply_theme3(label, LIVES_WIDGET_STATE_NORMAL);
5681     eventbox = lives_event_box_new();
5682     lives_container_add(LIVES_CONTAINER(eventbox), label);
5683     lives_event_box_set_above_child(LIVES_EVENT_BOX(eventbox), TRUE);
5684     lives_signal_sync_connect(LIVES_GUI_OBJECT(eventbox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
5685                               LIVES_GUI_CALLBACK(on_ebox_click),
5686                               LIVES_INT_TO_POINTER(row - 1));
5687     lives_table_attach(LIVES_TABLE(table), eventbox, 3, 4, row, row + 1,
5688                        (LiVESAttachOptions)(LIVES_EXPAND | LIVES_FILL),
5689                        (LiVESAttachOptions)(0), 0, 0);
5690     lives_free(notes);
5691     notes = lives_strdup("");
5692     row++;
5693   }
5694 
5695   lives_strfreev(lines);
5696   lives_free(notes);
5697 
5698   lives_widget_show_all(dialog);
5699 
5700   response = lives_dialog_run(LIVES_DIALOG(dialog));
5701   if (response < 0) {
5702     // user cancelled
5703     lives_list_free_all(&allids);
5704     return FALSE;
5705   }
5706 
5707   // set req->vidchoice and return
5708   lives_snprintf(req->vidchoice, 512, "%s", (char *)lives_list_nth_data(allids, response));
5709   lives_list_free_all(&allids);
5710   return TRUE;
5711 }
5712 
5713 
5714 /// disk quota window
5715 
lives_show_after(LiVESWidget * button,livespointer data)5716 static void lives_show_after(LiVESWidget * button, livespointer data) {
5717   LiVESWidget *showme = (LiVESWidget *)data;
5718   lives_general_button_clicked(LIVES_BUTTON(button), NULL);
5719   if (showme) lives_widget_show(showme);
5720 }
5721 
workdir_query_cb(LiVESWidget * w,LiVESWidget * dlg)5722 static void workdir_query_cb(LiVESWidget * w, LiVESWidget * dlg) {
5723   lives_widget_hide(dlg);
5724   if (do_workdir_query()) {
5725     if (lives_strcmp(prefs->workdir, future_prefs->workdir)) {
5726       char *msg = workdir_ch_warning();
5727       if (do_warning_dialog(msg)) {
5728         lives_free(msg);
5729         do_shutdown_msg();
5730         lives_widget_destroy(dlg);
5731         on_quit_activate(NULL, NULL);
5732       }
5733     } else {
5734       do_info_dialog(_("\nDirectory was not changed\n"));
5735     }
5736     *future_prefs->workdir = 0;
5737   }
5738   lives_widget_show(dlg);
5739 }
5740 
cleards_cb(LiVESWidget * w,LiVESWidget * dlg)5741 static void cleards_cb(LiVESWidget * w, LiVESWidget * dlg) {
5742   lives_widget_hide(dlg);
5743   on_cleardisk_activate(NULL, NULL);
5744   lives_widget_show(dlg);
5745 
5746 }
5747 
run_diskspace_dialog_cb(LiVESWidget * w,livespointer data)5748 void run_diskspace_dialog_cb(LiVESWidget * w, livespointer data) {
5749   run_diskspace_dialog();
5750 }
5751 
run_diskspace_dialog_idle(livespointer data)5752 boolean run_diskspace_dialog_idle(livespointer data) {
5753   run_diskspace_dialog();
5754   return FALSE;
5755 }
5756 
5757 ///////
5758 
manclips_del(LiVESWidget * button,_entryw * renamew)5759 static void manclips_del(LiVESWidget * button, _entryw * renamew) {
5760   boolean is_curset = FALSE;
5761   const char *setname = lives_entry_get_text(LIVES_ENTRY(renamew->entry));
5762   char *fsetname;
5763   if (!*setname) return;
5764 
5765 retry1:
5766   if (mainw->was_set && !lives_strcmp(setname, mainw->set_name)) {
5767     is_curset = TRUE;
5768     fsetname = lives_strdup(_("current set"));
5769   } else
5770     fsetname = lives_strdup_printf(_("set %s"), setname);
5771   if (check_for_executable(&capable->has_gio, EXEC_GIO)) mainw->add_trash_rb = TRUE;
5772   if (do_warning_dialogf(_("The %s will be permanently deleted from the disk.\n"
5773                            "Are you sure ?"), fsetname)) {
5774     mainw->add_trash_rb = FALSE;
5775     lives_free(fsetname);
5776     if (is_curset) {
5777       del_current_set(FALSE);
5778     } else {
5779       char *setdir = lives_build_path(prefs->workdir, setname, NULL);
5780       if (mainw->add_trash_rb && prefs->pref_trash) {
5781         if (send_to_trash(setdir) == LIVES_RESPONSE_CANCEL) goto retry1;
5782       } else lives_rmdir(setdir, TRUE);
5783       mainw->num_sets--;
5784     }
5785     if (!mainw->num_sets && !mainw->clips_available) {
5786       do_info_dialog(_("All Sets have been erased from the disk"));
5787       lives_widget_destroy(renamew->dialog);
5788       lives_widget_show(renamew->parent);
5789       lives_free(renamew);
5790       renamew = NULL;
5791       lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5792       return;
5793     }
5794     // refresh entry
5795     lives_entry_set_text(LIVES_ENTRY(renamew->entry), "");
5796     lives_widget_queue_draw(renamew->dialog);
5797   }
5798   mainw->add_trash_rb = FALSE;
5799   lives_free(fsetname);
5800 }
5801 
manclips_reload(LiVESWidget * button,_entryw * renamew)5802 static void manclips_reload(LiVESWidget * button, _entryw * renamew) {
5803   char *setname = (char *)lives_entry_get_text(LIVES_ENTRY(renamew->entry));
5804   if (!*setname) return;
5805   setname = lives_strdup(lives_entry_get_text(LIVES_ENTRY(renamew->entry)));
5806   if (mainw->was_set && !lives_strcmp(setname, mainw->set_name)) {
5807     do_info_dialogf(_("The set %s is already loaded !"), setname);
5808     return;
5809   }
5810   if (mainw->cliplist) {
5811     do_info_dialog(_("The current clips must be saved before reloading another set"));
5812     mainw->only_close = TRUE;
5813     if (!on_save_set_activate(button, NULL)) return;
5814     mainw->only_close = FALSE;
5815   }
5816 
5817   do_info_dialog(_("After reloading the Set you can inspect it and use it as normal.\n"
5818                    "Should you decide to delete it or re-save it, click on\nFile | Close/Save all Clips "
5819                    "in the menu of the Clip Editor\n"
5820                    "You will then be returned to the Manage Sets dialog,\n"
5821                    "where you may choose to continue this process further\n"));
5822   lives_widget_destroy(renamew->dialog);
5823   lives_widget_destroy(renamew->parent);
5824   lives_free(renamew);
5825   reload_set(setname);
5826   if (mainw->num_sets > -1) mainw->num_sets--;
5827   if (mainw->clips_available) mainw->cs_manage = TRUE;
5828 }
5829 
manclips_ok(LiVESWidget * button,LiVESWidget * dialog)5830 static void manclips_ok(LiVESWidget * button, LiVESWidget * dialog) {
5831   lives_general_button_clicked(LIVES_BUTTON(button), NULL);
5832 
5833   //mainw->cs_manage = TRUE;
5834   /// show list of all sets, excluding current
5835 
5836   lives_widget_hide(dialog);
5837 
5838   renamew = create_rename_dialog(3);
5839   if (!renamew) return; ///< no sets available
5840 
5841   renamew->parent = dialog;
5842 
5843   /// show buttons "Cancel", "Delete", "Reload"
5844 
5845   lives_signal_sync_connect(LIVES_GUI_OBJECT(renamew->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
5846                             LIVES_GUI_CALLBACK(lives_show_after), dialog);
5847 
5848   lives_button_ungrab_default_special(renamew->okbutton);
5849   lives_widget_destroy(renamew->okbutton);
5850 
5851   button = lives_dialog_add_button_from_stock(LIVES_DIALOG(renamew->dialog), LIVES_STOCK_DELETE,
5852            NULL, LIVES_RESPONSE_RESET);
5853 
5854   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
5855                             LIVES_GUI_CALLBACK(manclips_del), renamew);
5856 
5857   // reaload will exit dlg and set mainw->cs_managed, after close/save all we come back here
5858   button = lives_dialog_add_button_from_stock(LIVES_DIALOG(renamew->dialog), LIVES_STOCK_OPEN,
5859            _("_Reload"), LIVES_RESPONSE_YES);
5860 
5861   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
5862                             LIVES_GUI_CALLBACK(manclips_reload), renamew);
5863 
5864   lives_widget_show_all(renamew->dialog);
5865 }
5866 
manclips_cb(LiVESWidget * w,livespointer data)5867 static void manclips_cb(LiVESWidget * w, livespointer data) {
5868   LiVESWidget *parent = (LiVESWidget *)data;
5869   LiVESWidget *dialog;
5870   LiVESWidget *button;
5871   char *text, *extra;
5872 
5873   lives_widget_hide(parent);
5874 
5875   if (mainw->was_set) {
5876     extra = (_(" including the current set."));
5877   } else extra = lives_strdup("");
5878 
5879   text = lives_strdup_printf(_("<b>The current working directory contains %d Clip Sets%s</b>\n"
5880                                "You may be able to free up some disk space by deleting "
5881                                "unwanted ones.\n\n"
5882                                "After selecting an existing Set, "
5883                                "you will be presented with the options to "
5884                                "erase it from the disk\n"
5885                                "or to reload it first to inspect the contents\n\n"
5886                                "Please select an option below\n"), mainw->num_sets
5887                              + (mainw->was_set ? 1 : 0), extra);
5888   lives_free(extra);
5889   widget_opts.use_markup = TRUE;
5890   dialog = create_question_dialog(_("Manage Clipsets"), text);
5891   widget_opts.use_markup = FALSE;
5892   lives_free(text);
5893 
5894   button = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_GO_BACK,
5895            _("Go back"), LIVES_RESPONSE_CANCEL);
5896   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
5897                             LIVES_GUI_CALLBACK(lives_show_after), data);
5898 
5899   button = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_GO_FORWARD,
5900            _("Continue"), LIVES_RESPONSE_OK);
5901   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
5902                             LIVES_GUI_CALLBACK(manclips_ok), parent);
5903 
5904   lives_widget_show_all(dialog);
5905 }
5906 
5907 
5908 static _dsquotaw *dsq = NULL;
5909 
draw_dsu_widget(LiVESWidget * dsu_widget)5910 void draw_dsu_widget(LiVESWidget * dsu_widget) {
5911   double scale, xw, offs_x = 0;
5912   lives_painter_t *cr;
5913   int width, height;
5914 
5915   if (!dsq->dsu_surface) return;
5916   cr = lives_painter_create_from_surface(dsq->dsu_surface);
5917   if (!cr) return;
5918 
5919   if (capable->ds_used == -1 || capable->ds_free == -1 || capable->ds_tot == -1) return;
5920 
5921   width = lives_widget_get_allocation_width(dsu_widget);
5922   height = lives_widget_get_allocation_height(dsu_widget);
5923 
5924   if (width <= 0 || height <= 0) return;
5925 
5926   scale = (double)capable->ds_tot / (double)width;
5927 
5928   /// paint bg
5929   lives_painter_set_source_rgb(cr, 1., 1., 1.);
5930   lives_painter_rectangle(cr, 0, 0, width, height);
5931   lives_painter_fill(cr);
5932 
5933   /// space used by other apps
5934   xw = (double)(capable->ds_tot - capable->ds_used - capable->ds_free) / scale;
5935   lives_painter_set_source_rgb(cr, 0., 0., 1.);
5936   lives_painter_rectangle(cr, 0, 0, xw, height);
5937   lives_painter_fill(cr);
5938 
5939   offs_x += xw;
5940 
5941   /// space used by lives
5942   xw = (double)capable->ds_used / scale;
5943   lives_painter_set_source_rgb(cr, 0., 1., 1.);
5944   lives_painter_rectangle(cr, offs_x, 0, offs_x + xw, height);
5945   lives_painter_fill(cr);
5946 
5947   offs_x += xw;
5948 
5949   /// draw quota (if set)
5950   if (future_prefs->disk_quota > capable->ds_used) {
5951     uint64_t qq = future_prefs->disk_quota - capable->ds_used;
5952     if (qq > capable->ds_free - prefs->ds_warn_level) qq = capable->ds_free - prefs->ds_warn_level;
5953     if (qq > 0) {
5954       xw = (double)qq / scale;
5955       if (xw > 0.) {
5956         lives_painter_set_source_rgb(cr, 1., 1., 0.);
5957         lives_painter_rectangle(cr, offs_x, 0, offs_x + xw, height);
5958         lives_painter_fill(cr);
5959         offs_x += xw;
5960       }
5961     }
5962   }
5963 
5964   /// draw ds_free
5965   xw = (double)(capable->ds_free) / scale;
5966   if (prefs->ds_warn_level > 0)
5967     xw -= (double)prefs->ds_warn_level / scale;
5968   if (future_prefs->disk_quota > capable->ds_used)
5969     xw -= (double)(future_prefs->disk_quota - capable->ds_used) / scale;
5970 
5971   if (xw > 0.) {
5972     lives_painter_set_source_rgb(cr, 0., 1., 0.);
5973     lives_painter_rectangle(cr, offs_x, 0, offs_x + xw, height);
5974     lives_painter_fill(cr);
5975     offs_x += xw;
5976   }
5977 
5978   /// ds warning level
5979   if (prefs->ds_warn_level > 0) {
5980     xw = (double)(prefs->ds_warn_level - prefs->ds_crit_level) / scale;
5981     if (xw > 0.) {
5982       lives_painter_set_source_rgb(cr, 1., .5, 0.);
5983       lives_painter_rectangle(cr, offs_x, 0, offs_x + xw, height);
5984       lives_painter_fill(cr);
5985       offs_x += xw;
5986     }
5987   }
5988 
5989   /// ds critical level
5990   if (prefs->ds_crit_level > 0) {
5991     xw = (double)prefs->ds_crit_level / scale;
5992     if (xw > 0.) {
5993       lives_painter_set_source_rgb(cr, 1., 0., 0.);
5994       lives_painter_rectangle(cr, offs_x, 0, offs_x + xw, height);
5995       lives_painter_fill(cr);
5996       offs_x += xw;
5997     }
5998   }
5999   lives_painter_destroy(cr);
6000   lives_widget_queue_draw(dsu_widget);
6001 }
6002 
6003 
dsu_set_toplabel(void)6004 static void dsu_set_toplabel(void) {
6005   char *ltext = NULL, *dtxt, *dtxt2;
6006   widget_opts.text_size = LIVES_TEXT_SIZE_LARGE;
6007 
6008   if (mainw->dsu_valid && !dsq->scanning) {
6009     if (capable->ds_free < prefs->ds_crit_level) {
6010       if (!capable->mountpoint) capable->mountpoint = get_mountpoint_for(prefs->workdir);
6011       dtxt = lives_format_storage_space_string(prefs->ds_crit_level);
6012       dtxt2 = lives_markup_escape_text(capable->mountpoint, -1);
6013       ltext = lives_strdup_printf(_("<b>ALERT ! FREE SPACE IN %s IS BELOW THE CRITICAL LEVEL OF %s\n"
6014                                     "YOU SHOULD EXIT LIVES IMMEDIATELY TO AVOID POSSIBLE DATA LOSS</b>"),
6015                                   dtxt2, dtxt);
6016       lives_free(dtxt); lives_free(dtxt2);
6017       widget_opts.use_markup = TRUE;
6018       lives_label_set_text(LIVES_LABEL(dsq->top_label), ltext);
6019       widget_opts.use_markup = FALSE;
6020       widget_opts.text_size = LIVES_TEXT_SIZE_NORMAL;
6021       if (!dsq->crit_dism) {
6022         dsq->crit_dism = TRUE;
6023         lives_free(ltext);
6024         ltext = ds_critical_msg(prefs->workdir, &capable->mountpoint, capable->ds_free);
6025         widget_opts.use_markup = TRUE;
6026         do_abort_ok_dialog(ltext);
6027         widget_opts.use_markup = FALSE;
6028       }
6029       lives_free(ltext);
6030       return;
6031     }
6032     if (capable->ds_free < prefs->ds_warn_level) {
6033       if (!capable->mountpoint) capable->mountpoint = get_mountpoint_for(prefs->workdir);
6034       dtxt = lives_format_storage_space_string(prefs->ds_crit_level);
6035       ltext = lives_strdup_printf(_("WARNING ! Free space in %s is below the warning level of %s\n"
6036                                     "Action should be taken to remedy this"),
6037                                   capable->mountpoint, dtxt);
6038       lives_free(dtxt);
6039     } else if (prefs->disk_quota) {
6040       if (capable->ds_used > prefs->disk_quota) {
6041         uint64_t xs = capable->ds_used - prefs->disk_quota;
6042         dtxt = lives_format_storage_space_string(xs);
6043         ltext = lives_strdup_printf(_("WARNING ! LiVES has exceeded its quota by %s"), dtxt);
6044         lives_free(dtxt);
6045       } else if (capable->ds_used >= (int64_t)((double)prefs->disk_quota * prefs->quota_limit / 100.)) {
6046         double pcused = (double)capable->ds_used / (double)prefs->disk_quota * 100.;
6047         ltext = lives_strdup_printf(_("ATTENTION: LiVES is currently using over %d%% of its assigned quota"), (int)pcused);
6048       } else if (prefs->disk_quota - capable->ds_used + prefs->ds_warn_level > capable->ds_free) {
6049         ltext = lives_strdup(_("ATTENTION ! There is insufficient free space on the disk for LiVES' current quota"));
6050       }
6051     }
6052   }
6053   if (!ltext) {
6054     ltext = lives_strdup(_("LiVES can help limit the amount of diskspace used by projects (sets)."));
6055   }
6056   lives_label_set_text(LIVES_LABEL(dsq->top_label), ltext);
6057   lives_free(ltext);
6058   widget_opts.text_size = LIVES_TEXT_SIZE_NORMAL;
6059 }
6060 
dsu_label_notset(void)6061 LIVES_LOCAL_INLINE char *dsu_label_notset(void) {return _("Value not set");}
dsu_label_calculating(void)6062 LIVES_LOCAL_INLINE char *dsu_label_calculating(void) {return _("Calculating....");}
6063 
update_dsu(livespointer data)6064 boolean update_dsu(livespointer data) {
6065   static boolean set_label = FALSE;
6066   int64_t dsu = -1;
6067   char *txt;
6068   if ((!dsq || dsq->scanning) && (dsu = disk_monitor_check_result(prefs->workdir)) < 0) {
6069     if (!dsq || !dsq->visible) {
6070       return FALSE;
6071     }
6072     if (!set_label) {
6073       set_label = TRUE;
6074       lives_label_set_text(LIVES_LABEL(dsq->used_label), (txt = dsu_label_calculating()));
6075       lives_free(txt);
6076     }
6077   } else {
6078     if (mainw->dsu_valid) {
6079       if (dsu > -1) capable->ds_used = dsu;
6080       dsu = capable->ds_used;
6081       mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsu, 0);
6082       capable->ds_free = dsu;
6083       dsq->scanning = FALSE;
6084       if (mainw->dsu_widget) {
6085         txt = lives_format_storage_space_string(capable->ds_used);
6086         lives_label_set_text(LIVES_LABEL(dsq->used_label), txt);
6087         lives_free(txt);
6088         draw_dsu_widget(mainw->dsu_widget);
6089         dsu_set_toplabel();
6090         dsu_fill_details(NULL, NULL);
6091         qslider_changed(dsq->slider, dsq);
6092         if (capable->ds_free < prefs->ds_warn_level || mainw->has_session_workdir)
6093           lives_widget_set_sensitive(dsq->button, FALSE);
6094         if (capable->ds_free < prefs->ds_crit_level) {
6095           lives_widget_set_no_show_all(dsq->abort_button, FALSE);
6096           lives_widget_show_all(dsq->abort_button);
6097         }
6098       }
6099       set_label = FALSE;
6100       mainw->dsu_valid = TRUE;
6101       return FALSE;
6102     }
6103   }
6104   return TRUE;
6105 }
6106 
qslider_changed(LiVESWidget * slid,livespointer data)6107 static void qslider_changed(LiVESWidget * slid, livespointer data) {
6108   char *txt, *dtxt;
6109   if (mainw->dsu_valid && !dsq->scanning) {
6110     uint64_t min = capable->ds_used;
6111     uint64_t max = capable->ds_free + min - prefs->ds_warn_level;
6112     double value = 0.;
6113     if (dsq->setting) {
6114       value = lives_range_get_value(LIVES_RANGE(slid)) / 100.;
6115       lives_signal_handler_block(dsq->checkbutton, dsq->checkfunc);
6116       lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(dsq->checkbutton), FALSE);
6117       lives_signal_handler_unblock(dsq->checkbutton, dsq->checkfunc);
6118       future_prefs->disk_quota = (uint64_t)(min + value * (max - min) + .5);
6119       draw_dsu_widget(mainw->dsu_widget);
6120     } else {
6121       if (future_prefs->disk_quota > 0) {
6122         if (future_prefs->disk_quota >= capable->ds_used) {
6123           uint64_t dq = future_prefs->disk_quota;
6124           dq -= min;
6125           value = 100. * (double)dq / (double)(max - min);
6126           if (value > 100.) value = 100.;
6127         }
6128       }
6129       lives_signal_handler_block(dsq->slider, dsq->sliderfunc);
6130       lives_range_set_value(LIVES_RANGE(dsq->slider), value);
6131       lives_signal_handler_unblock(dsq->slider, dsq->sliderfunc);
6132     }
6133   }
6134 
6135   if (future_prefs->disk_quota > 0.) {
6136     txt = lives_format_storage_space_string(future_prefs->disk_quota);
6137     dtxt = lives_strdup_printf("<b>%s</b>", txt);
6138     widget_opts.use_markup = TRUE;
6139     lives_label_set_text(LIVES_LABEL(dsq->vlabel), dtxt);
6140     widget_opts.use_markup = FALSE;
6141     lives_free(txt); lives_free(dtxt);
6142     if (mainw->dsu_valid && !dsq->scanning) {
6143       double pcused = 100. * (double)capable->ds_used
6144                       / (double)future_prefs->disk_quota;
6145 
6146       if (pcused < 100.) txt = lives_strdup_printf(_("%.2f%% used"), pcused);
6147       else {
6148         txt = lives_strdup_printf(_("<b>%.2f%% used !!</b>"), pcused);
6149         widget_opts.use_markup = TRUE;
6150       }
6151       lives_label_set_text(LIVES_LABEL(dsq->pculabel), txt);
6152       widget_opts.use_markup = FALSE;
6153       lives_free(txt);
6154       if (pcused >= prefs->quota_limit) {
6155         txt = lives_strdup_printf(_("LiVES is currently using over %d%% of its available quota"), (int)prefs->quota_limit);
6156         show_warn_image(dsq->pculabel, txt);
6157         lives_free(txt);
6158       } else hide_warn_image(dsq->pculabel);
6159     } else {
6160       hide_warn_image(dsq->pculabel);
6161       lives_label_set_text(LIVES_LABEL(dsq->pculabel), _("Calculating %% used"));
6162     }
6163   } else {
6164     hide_warn_image(dsq->pculabel);
6165     lives_label_set_text(LIVES_LABEL(dsq->pculabel), NULL);
6166     txt = dsu_label_notset();
6167     dtxt = lives_strdup_printf("<b>%s</b>", txt);
6168     widget_opts.use_markup = TRUE;
6169     lives_label_set_text(LIVES_LABEL(dsq->vlabel), dtxt);
6170     widget_opts.use_markup = FALSE;
6171     lives_free(dtxt); lives_free(txt);
6172   }
6173 }
6174 
dsq_check_toggled(LiVESWidget * cbutt,livespointer data)6175 static void dsq_check_toggled(LiVESWidget * cbutt, livespointer data) {
6176   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(cbutt))) {
6177     future_prefs->disk_quota = 0;
6178   } else {
6179     lives_widget_set_sensitive(dsq->slider, TRUE);
6180     future_prefs->disk_quota = prefs->disk_quota;
6181   }
6182   dsq->setting = FALSE;
6183   qslider_changed(dsq->slider, NULL);
6184   dsq->setting = TRUE;
6185   draw_dsu_widget(mainw->dsu_widget);
6186 }
6187 
6188 static boolean mouse_on = FALSE;
6189 
dsu_widget_clicked(LiVESWidget * widget,LiVESXEventButton * event,livespointer is_clickp)6190 static boolean dsu_widget_clicked(LiVESWidget * widget, LiVESXEventButton * event, livespointer is_clickp) {
6191   boolean is_click;
6192   is_click = LIVES_POINTER_TO_INT(is_clickp);
6193   if (is_click) mouse_on = TRUE;
6194   else if (!mouse_on) return TRUE;
6195 
6196   if (!mainw->dsu_valid || dsq->scanning) return TRUE;
6197   else {
6198     int width = lives_widget_get_allocation_width(widget);
6199     if (width <= 0) return TRUE;
6200     else {
6201       int x;
6202       lives_widget_get_pointer((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
6203                                widget, &x, NULL);
6204       if (x > 0) {
6205         uint64_t min = capable->ds_tot - capable->ds_free;
6206         uint64_t max = capable->ds_tot - prefs->ds_warn_level;
6207         double scale = (double)capable->ds_tot / (double)width;
6208         double value = (double)x * scale;
6209         value -= (double)min;
6210         value = 100. * value / (double)(max - min);
6211         if (value < 0.) value = 0.;
6212         if (value > 100.) value = 100.;
6213         lives_range_set_value(LIVES_RANGE(dsq->slider), value);
6214 	// *INDENT-OFF*
6215       }}}
6216   // *INDENT-ON*
6217 
6218   return TRUE;
6219 }
6220 
dsu_widget_released(LiVESWidget * widget,LiVESXEventButton * event,livespointer is_clickp)6221 static boolean dsu_widget_released(LiVESWidget * widget, LiVESXEventButton * event, livespointer is_clickp) {
6222   mouse_on = FALSE;
6223   return TRUE;
6224 }
6225 
dsu_ok_clicked(LiVESWidget * butt,LiVESWidget * toshow)6226 static void dsu_ok_clicked(LiVESWidget * butt, LiVESWidget * toshow) {
6227   dsq->visible = FALSE;
6228   mainw->dsu_widget = NULL;
6229   lives_show_after(butt, toshow);
6230 }
6231 
dsu_fill_details(LiVESWidget * widget,livespointer data)6232 static void dsu_fill_details(LiVESWidget * widget, livespointer data) {
6233   uint64_t dsval;
6234   char *txt;
6235   LiVESWidget *layout2;
6236 
6237   if (dsq->exp_layout) lives_widget_destroy(dsq->exp_layout);
6238   dsq->exp_layout = NULL;
6239   if (!lives_expander_get_expanded(LIVES_EXPANDER(dsq->expander))) {
6240     widget_opts.use_markup = TRUE;
6241     lives_expander_set_label(LIVES_EXPANDER(dsq->expander), _("<b>Full _Details</b>"));
6242     widget_opts.use_markup = FALSE;
6243     return;
6244   }
6245 
6246   widget_opts.use_markup = TRUE;
6247   lives_expander_set_label(LIVES_EXPANDER(dsq->expander), _("<b>Hide _Details</b>"));
6248   widget_opts.use_markup = FALSE;
6249 
6250   dsq->exp_layout = lives_layout_new(LIVES_BOX(dsq->exp_vbox));
6251   layout2 = dsq->exp_layout;
6252 
6253   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Working directory"), TRUE);
6254   lives_layout_add_label(LIVES_LAYOUT(layout2), prefs->workdir, TRUE);
6255 
6256   lives_layout_add_row(LIVES_LAYOUT(layout2));
6257   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Mount point"), TRUE);
6258   if (!capable->mountpoint) capable->mountpoint = get_mountpoint_for(prefs->workdir);
6259   lives_layout_add_label(LIVES_LAYOUT(layout2), capable->mountpoint, TRUE);
6260 
6261   lives_layout_add_row(LIVES_LAYOUT(layout2));
6262   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Total size"), TRUE);
6263   if (!mainw->dsu_valid || dsq->scanning)
6264     txt = dsu_label_calculating();
6265   else
6266     txt = lives_format_storage_space_string(capable->ds_tot);
6267   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6268   lives_free(txt);
6269 
6270   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Disk space free"), TRUE);
6271   if (!mainw->dsu_valid || dsq->scanning)
6272     txt = dsu_label_calculating();
6273   else
6274     txt = lives_format_storage_space_string(capable->ds_free);
6275   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6276   lives_free(txt);
6277 
6278   if (mainw->dsu_valid && !dsq->scanning) {
6279     if (capable->ds_free <= prefs->ds_crit_level)
6280       show_warn_image(widget_opts.last_label, _("Free diskspace is below the critical level"));
6281     else if (capable->ds_free <= prefs->ds_warn_level)
6282       show_warn_image(widget_opts.last_label, _("Free diskspace is below the warning level"));
6283   }
6284 
6285   lives_layout_add_row(LIVES_LAYOUT(layout2));
6286   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Used by other applications"), TRUE);
6287   if (!mainw->dsu_valid || dsq->scanning)
6288     txt = dsu_label_calculating();
6289   else {
6290     dsval = capable->ds_tot - capable->ds_free - capable->ds_used;
6291     txt = lives_format_storage_space_string(dsval);
6292   }
6293   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6294   lives_free(txt);
6295 
6296   //lives_layout_add_row(LIVES_LAYOUT(layout2));
6297   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Used by LiVES"), TRUE);
6298 
6299   if (!mainw->dsu_valid || dsq->scanning)
6300     txt = dsu_label_calculating();
6301   else
6302     txt = lives_format_storage_space_string(capable->ds_used);
6303   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6304   lives_free(txt);
6305 
6306   lives_layout_add_row(LIVES_LAYOUT(layout2));
6307   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Sets on disk"), TRUE);
6308   txt = lives_strdup_printf("%d", mainw->num_sets + mainw->was_set ? 1 : 0);
6309   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6310   lives_free(txt);
6311 
6312   //lives_layout_add_row(LIVES_LAYOUT(layout2));
6313   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Currently opened clips"), TRUE);
6314   txt = lives_strdup_printf("%d", mainw->clips_available);
6315   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6316   lives_free(txt);
6317 
6318   lives_layout_add_row(LIVES_LAYOUT(layout2));
6319   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Disk quota"), TRUE);
6320   if (prefs->disk_quota)
6321     txt = lives_format_storage_space_string(prefs->disk_quota);
6322   else
6323     txt = dsu_label_notset();
6324   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6325   lives_free(txt);
6326 
6327   if (prefs->disk_quota) {
6328     double pcu = 0.;
6329 
6330     if (!mainw->dsu_valid || dsq->scanning)
6331       txt = dsu_label_calculating();
6332     else {
6333       uint64_t qq = prefs->disk_quota, over = 0;
6334       if (qq > capable->ds_used) {
6335         qq -= capable->ds_used;
6336         if (qq + prefs->ds_warn_level > capable->ds_free)
6337           over = qq + prefs->ds_warn_level - capable->ds_free;
6338         if (over) {
6339           char *txt2;
6340           txt = lives_format_storage_space_string(over);
6341           txt2 = lives_strdup_printf(_("Quota is reduced by %s due to free disk space limitations"), txt);
6342           show_warn_image(widget_opts.last_label, txt2);
6343           lives_free(txt); lives_free(txt2);
6344         }
6345         if (qq < over) qq = 0;
6346         else qq -= over;
6347         pcu = (double)qq / (double)prefs->disk_quota;
6348       }
6349       txt = lives_strdup_printf("%.2f%%", pcu * 100.);
6350     }
6351 
6352     lives_layout_add_label(LIVES_LAYOUT(layout2), _("Unused quota"), TRUE);
6353     lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6354     lives_free(txt);
6355     pcu = 100. * (1. - pcu);
6356     if (pcu > prefs->quota_limit) {
6357       txt = lives_strdup_printf(_("LiVES is currently using over %d%% of its available quota"), (int)prefs->quota_limit);
6358       show_warn_image(widget_opts.last_label, txt);
6359       lives_free(txt);
6360     }
6361   }
6362   lives_layout_add_row(LIVES_LAYOUT(layout2));
6363   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Disk warning level"), TRUE);
6364   lives_widget_set_tooltip_text(widget_opts.last_label, H_("value can be set in Preferences . Warnings"));
6365   if (prefs->ds_warn_level)
6366     txt = lives_format_storage_space_string(prefs->ds_warn_level);
6367   else
6368     txt = dsu_label_notset();
6369   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6370   lives_free(txt);
6371 
6372   //lives_layout_add_row(LIVES_LAYOUT(layout2));
6373   lives_layout_add_label(LIVES_LAYOUT(layout2), _("Disk critical level"), TRUE);
6374   lives_widget_set_tooltip_text(widget_opts.last_label, H_("value can be set in Preferences . Warnings"));
6375   if (prefs->ds_crit_level)
6376     txt = lives_format_storage_space_string(prefs->ds_crit_level);
6377   else
6378     txt = dsu_label_notset();
6379   lives_layout_add_label(LIVES_LAYOUT(layout2), txt, TRUE);
6380   lives_free(txt);
6381   lives_widget_show_all(dsq->exp_layout);
6382 }
6383 
6384 
changequota_cb(LiVESWidget * butt,livespointer data)6385 static void changequota_cb(LiVESWidget * butt, livespointer data) {
6386   static char *otxt = NULL;
6387 
6388   if (dsq->scanning || !mainw->dsu_valid) {
6389     lives_label_set_text(LIVES_LABEL(dsq->inst_label), _("Still calculating...please wait and try again..."));
6390     return;
6391   }
6392 
6393   if (!dsq->setting) {
6394     otxt = lives_strdup(lives_standard_button_get_label(LIVES_BUTTON(butt)));
6395     widget_opts.use_markup = TRUE;
6396     lives_label_set_text(LIVES_LABEL(dsq->inst_label), _("<b>Change the quota by clicking in the free space area "
6397                          "in the disk map above,\n"
6398                          "or by dragging the slider below</b>"));
6399     widget_opts.use_markup = FALSE;
6400     lives_widget_set_sensitive(dsq->checkbutton, TRUE);
6401     lives_widget_set_sensitive(dsq->vvlabel, TRUE);
6402     lives_widget_set_sensitive(dsq->vlabel, TRUE);
6403     lives_widget_set_sensitive(dsq->slider, TRUE);
6404     lives_standard_button_set_label(LIVES_BUTTON(butt), _("APPLY _QUOTA"));
6405     lives_widget_hide(dsq->note_label);
6406     lives_widget_set_no_show_all(dsq->resbutton, FALSE);
6407     lives_widget_show_all(dsq->resbutton);
6408     dsq->setting = TRUE;
6409   } else {
6410     pref_factory_int64(PREF_DISK_QUOTA, future_prefs->disk_quota, TRUE);
6411     dsu_set_toplabel();
6412     widget_opts.use_markup = TRUE;
6413     lives_label_set_text(LIVES_LABEL(dsq->inst_label), _("<b>Updated !</b>"));
6414     widget_opts.use_markup = FALSE;
6415     lives_widget_set_frozen(dsq->checkbutton, TRUE);
6416     lives_widget_set_frozen(dsq->vvlabel, TRUE);
6417     lives_widget_set_frozen(dsq->vlabel, TRUE);
6418     lives_widget_set_frozen(dsq->slider, TRUE);
6419     lives_standard_button_set_label(LIVES_BUTTON(dsq->button), otxt);
6420     dsq->setting = FALSE;
6421     dsu_fill_details(NULL, NULL);
6422     qslider_changed(dsq->slider, dsq);
6423   }
6424 }
6425 
resquota_cb(LiVESWidget * butt,livespointer data)6426 static void resquota_cb(LiVESWidget * butt, livespointer data) {
6427   lives_widget_hide(butt);
6428   lives_widget_show(dsq->note_label);
6429   lives_label_set_text(LIVES_LABEL(dsq->inst_label), NULL);
6430   future_prefs->disk_quota = prefs->disk_quota;
6431   lives_signal_handler_block(dsq->checkbutton, dsq->checkfunc);
6432   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(dsq->checkbutton), !prefs->disk_quota);
6433   lives_signal_handler_unblock(dsq->checkbutton, dsq->checkfunc);
6434 
6435   dsq->setting = TRUE;
6436   changequota_cb(dsq->button, NULL);
6437   lives_label_set_text(LIVES_LABEL(dsq->inst_label), NULL);
6438   draw_dsu_widget(mainw->dsu_widget);
6439 }
6440 
dsu_abort_clicked(LiVESWidget * butt,livespointer data)6441 static void dsu_abort_clicked(LiVESWidget * butt, livespointer data) {
6442   if (do_abort_check()) abort();
6443 }
6444 
run_diskspace_dialog(void)6445 void run_diskspace_dialog(void) {
6446   LiVESWidget *dialog, *dialog_vbox;
6447   LiVESWidget *layout;
6448   LiVESWidget *label;
6449   LiVESWidget *entry;
6450   LiVESWidget *button;
6451   LiVESWidget *hbox, *hbox2;
6452   LiVESWidget *cbut;
6453   LiVESWidget *okbutton;
6454   LiVESWidget *rembutton;
6455 
6456   LiVESBox *aar;
6457 
6458   LiVESWidgetColor colr;
6459 
6460   char *title, *tmp;
6461   int wofl;
6462 
6463   /// kick off a bg process to get free ds and ds used
6464 
6465   if (!dsq) dsq = (_dsquotaw *)lives_calloc(1, sizeof(_dsquotaw));
6466 
6467   dsq->scanning = TRUE;
6468   disk_monitor_start(prefs->workdir);
6469 
6470   dsq->setting = FALSE;
6471   dsq->visible = TRUE;
6472   dsq->crit_dism = FALSE;
6473 
6474   dsq->exp_layout = NULL;
6475 
6476   if (dsq->dsu_surface) lives_painter_surface_destroy(dsq->dsu_surface);
6477   dsq->dsu_surface = NULL;
6478 
6479   if (prefsw) lives_widget_hide(prefsw->prefs_dialog);
6480 
6481   title = (_("Disk Space Quota"));
6482 
6483   dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
6484   lives_signal_handlers_disconnect_by_func(dialog, LIVES_GUI_CALLBACK(return_true), NULL);
6485 
6486   lives_free(title);
6487 
6488   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
6489   layout = lives_layout_new(LIVES_BOX(dialog_vbox));
6490 
6491   widget_opts.text_size = LIVES_TEXT_SIZE_LARGE;
6492   widget_opts.justify = LIVES_JUSTIFY_CENTER;
6493   dsq->top_label = lives_layout_add_label(LIVES_LAYOUT(layout), NULL, FALSE);
6494   dsu_set_toplabel();
6495 
6496   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
6497   widget_opts.text_size = LIVES_TEXT_SIZE_NORMAL;
6498 
6499   if (prefs->startup_phase) add_fill_to_box(LIVES_BOX(dialog_vbox));
6500   else {
6501     lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
6502 
6503     hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
6504 
6505     entry = lives_standard_entry_new(_("Current working directory"), prefs->workdir, -1, PATH_MAX,
6506                                      LIVES_BOX(hbox),
6507                                      H_("The directory where LiVES will save projects (sets)"));
6508 
6509     lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
6510 
6511     //lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6512 
6513     //hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
6514     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6515 
6516     button = lives_standard_button_new_from_stock(LIVES_STOCK_PREFERENCES, _("Change Directory"),
6517              DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6518     lives_widget_set_focus_on_click(button, FALSE);
6519 
6520     lives_box_pack_start(LIVES_BOX(hbox), button, FALSE, TRUE, widget_opts.packing_width * 4);
6521 
6522     lives_signal_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
6523                          LIVES_GUI_CALLBACK(workdir_query_cb), dialog);
6524   }
6525 
6526   lives_layout_add_row(LIVES_LAYOUT(layout));
6527 
6528   widget_opts.text_size = LIVES_TEXT_SIZE_LARGE;
6529   widget_opts.use_markup = TRUE;
6530   lives_layout_add_label(LIVES_LAYOUT(layout), (_("<b>Disk space used by LiVES:</b>")), TRUE);
6531   widget_opts.use_markup = FALSE;
6532 
6533   dsq->used_label = lives_layout_add_label(LIVES_LAYOUT(layout), NULL, TRUE);
6534 
6535   if (!capable->mountpoint) capable->mountpoint = get_mountpoint_for(prefs->workdir);
6536   if (capable->mountpoint) {
6537     char *txt = lives_strdup_printf(_("in %s"), capable->mountpoint);
6538     lives_layout_add_label(LIVES_LAYOUT(layout), txt, TRUE);
6539     lives_free(txt);
6540   }
6541 
6542   widget_opts.text_size = LIVES_TEXT_SIZE_NORMAL;
6543 
6544   add_hsep_to_box(LIVES_BOX(dialog_vbox));
6545 
6546   hbox = lives_hbox_new(FALSE, 0);
6547   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, TRUE, widget_opts.packing_height >> 1);
6548 
6549   if (prefs->startup_phase) add_fill_to_box(LIVES_BOX(dialog_vbox));
6550 
6551   layout = lives_layout_new(LIVES_BOX(dialog_vbox));
6552 
6553   /// dsu widget
6554   mainw->dsu_widget = lives_standard_drawing_area_new(LIVES_GUI_CALLBACK(all_expose), &dsq->dsu_surface);
6555   lives_widget_add_events(mainw->dsu_widget, LIVES_BUTTON_PRESS_MASK | LIVES_BUTTON_RELEASE_MASK | LIVES_BUTTON1_MOTION_MASK);
6556 
6557   lives_signal_sync_connect(LIVES_GUI_OBJECT(mainw->dsu_widget), LIVES_WIDGET_BUTTON_PRESS_EVENT,
6558                             LIVES_GUI_CALLBACK(dsu_widget_clicked), LIVES_INT_TO_POINTER(TRUE));
6559 
6560   lives_signal_sync_connect(LIVES_GUI_OBJECT(mainw->dsu_widget), LIVES_WIDGET_MOTION_NOTIFY_EVENT,
6561                             LIVES_GUI_CALLBACK(dsu_widget_clicked), LIVES_INT_TO_POINTER(FALSE));
6562 
6563   lives_signal_sync_connect(LIVES_GUI_OBJECT(mainw->dsu_widget), LIVES_WIDGET_BUTTON_RELEASE_EVENT,
6564                             LIVES_GUI_CALLBACK(dsu_widget_released), NULL);
6565 
6566   lives_box_pack_start(LIVES_BOX(hbox), mainw->dsu_widget, TRUE, TRUE, 0);
6567 
6568   lives_widget_set_size_request(mainw->dsu_widget, -1, widget_opts.css_min_height);
6569 
6570   hbox = lives_hbox_new(TRUE, 0);
6571   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, TRUE, 0);
6572 
6573   colr.alpha = 1.;
6574 
6575   hbox2 = lives_hbox_new(FALSE, 0);
6576   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6577   colr.red = colr.green = 0.; colr.blue = 1.;
6578   cbut = lives_color_button_new_with_color(&colr);
6579   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6580   label = lives_standard_label_new(_("Used by other apps"));
6581   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6582 
6583   hbox2 = lives_hbox_new(FALSE, 0);
6584   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6585   colr.red = 0.; colr.green = colr.blue = 1.;
6586   cbut = lives_color_button_new_with_color(&colr);
6587   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6588   label = lives_standard_label_new(_("Used by LiVES"));
6589   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6590 
6591   hbox2 = lives_hbox_new(FALSE, 0);
6592   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6593   colr.red = colr.green = 1.; colr.blue = 0.;
6594   cbut = lives_color_button_new_with_color(&colr);
6595   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6596   label = lives_standard_label_new(_("Quota"));
6597   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6598 
6599   hbox2 = lives_hbox_new(FALSE, 0);
6600   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6601   colr.red = colr.blue = 0.; colr.green = 1.;
6602   cbut = lives_color_button_new_with_color(&colr);
6603   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6604   label = lives_standard_label_new(_("Free space"));
6605   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6606 
6607   hbox2 = lives_hbox_new(FALSE, 0);
6608   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6609   colr.red = 1.; colr.green = .5; colr.blue = 0.;
6610   cbut = lives_color_button_new_with_color(&colr);
6611   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6612   label = lives_standard_label_new(_("Warn level"));
6613   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6614 
6615   hbox2 = lives_hbox_new(FALSE, 0);
6616   lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, TRUE, 0);
6617   colr.red = 1.; colr.green = colr.blue = 0.;
6618   cbut = lives_color_button_new_with_color(&colr);
6619   lives_box_pack_start(LIVES_BOX(hbox2), cbut, FALSE, FALSE, widget_opts.packing_width);
6620   label = lives_standard_label_new(_("Critical level"));
6621   lives_box_pack_start(LIVES_BOX(hbox2), label, FALSE, FALSE, widget_opts.packing_width);
6622 
6623   //// expander section ////
6624   dsq->exp_vbox = lives_vbox_new(FALSE, 0);
6625 
6626   if (prefs->startup_phase) add_fill_to_box(LIVES_BOX(dialog_vbox));
6627 
6628   layout = lives_layout_new(LIVES_BOX(dialog_vbox));
6629   hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6630   dsq->expander = lives_standard_expander_new(NULL, LIVES_BOX(hbox), dsq->exp_vbox);
6631   lives_layout_expansion_row_new(LIVES_LAYOUT(layout), dsq->expander);
6632 
6633   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(dsq->expander), LIVES_WIDGET_ACTIVATE_SIGNAL,
6634                                   LIVES_GUI_CALLBACK(dsu_fill_details), dsq);
6635 
6636   dsu_fill_details(dsq->expander, dsq);
6637 
6638   lives_layout_add_row(LIVES_LAYOUT(layout));
6639 
6640   wofl = widget_opts.filler_len;
6641   widget_opts.filler_len = def_widget_opts.filler_len * 6;
6642   lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6643   widget_opts.filler_len = wofl;
6644 
6645   if (prefs->startup_phase) lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
6646 
6647   widget_opts.use_markup = TRUE;
6648   if (!mainw->has_session_workdir)
6649     dsq->note_label = lives_layout_add_label(LIVES_LAYOUT(layout), (_("Note: LiVES cannot <b>guarantee"
6650                       "</b> not to exceed its quota\n"
6651                       "but it can warn you if this is detected.")), TRUE);
6652   else
6653     dsq->note_label = lives_layout_add_label(LIVES_LAYOUT(layout), (_("<b>Quota checking is disabled when workdir\n"
6654                       "is set via commandline option.</b>")), TRUE);
6655 
6656   widget_opts.use_markup = FALSE;
6657   hbox = widget_opts.last_container;
6658 
6659   dsq->resbutton = lives_standard_button_new_from_stock(LIVES_STOCK_UNDO, _("Reset"),
6660                    DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6661   lives_widget_set_focus_on_click(dsq->resbutton, FALSE);
6662 
6663   lives_box_pack_start(LIVES_BOX(hbox), dsq->resbutton, FALSE, FALSE, widget_opts.packing_width * 4);
6664 
6665   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(dsq->resbutton), LIVES_WIDGET_CLICKED_SIGNAL,
6666                                   LIVES_GUI_CALLBACK(resquota_cb), NULL);
6667 
6668   lives_widget_set_no_show_all(dsq->resbutton, TRUE);
6669 
6670   // quota button
6671 
6672   hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6673 
6674   dsq->button = lives_standard_button_new_from_stock(LIVES_STOCK_PREFERENCES, _("Change _Quota"),
6675                 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6676   lives_widget_set_focus_on_click(dsq->button, FALSE);
6677 
6678   lives_box_pack_start(LIVES_BOX(hbox), dsq->button, FALSE, FALSE, widget_opts.packing_width * 4);
6679 
6680   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(dsq->button), LIVES_WIDGET_CLICKED_SIGNAL,
6681                                   LIVES_GUI_CALLBACK(changequota_cb), NULL);
6682 
6683   dsq->inst_label = lives_layout_add_label(LIVES_LAYOUT(layout), NULL, TRUE);
6684 
6685   if (prefs->startup_phase) add_fill_to_box(LIVES_BOX(dialog_vbox));
6686 
6687   layout = lives_layout_new(LIVES_BOX(dialog_vbox));
6688 
6689   lives_layout_add_label(LIVES_LAYOUT(layout), (_("Quota:")), TRUE);
6690 
6691   hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6692   dsq->checkbutton =
6693     lives_standard_check_button_new((tmp = (_("Unlimited"))), future_prefs->disk_quota == 0,
6694                                     LIVES_BOX(hbox), NULL);
6695 
6696   lives_widget_set_frozen(dsq->checkbutton, TRUE);
6697   lives_widget_set_frozen(widget_opts.last_label, TRUE);
6698 
6699   dsq->checkfunc = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(dsq->checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
6700                    LIVES_GUI_CALLBACK(dsq_check_toggled), NULL);
6701 
6702   dsq->vvlabel = lives_layout_add_label(LIVES_LAYOUT(layout), (_("Value:")), TRUE);
6703   lives_widget_set_frozen(dsq->vvlabel, TRUE);
6704   dsq->vlabel = label = lives_layout_add_label(LIVES_LAYOUT(layout), NULL, TRUE);
6705   lives_widget_set_frozen(dsq->vlabel, TRUE);
6706   lives_label_set_width_chars(LIVES_LABEL(dsq->vlabel), 12);
6707 
6708   add_fill_to_box(LIVES_BOX(lives_widget_get_parent(label)));
6709 
6710   dsq->slider = lives_standard_hscale_new(NULL);
6711   lives_widget_set_size_request(dsq->slider, DEF_SLIDER_WIDTH * 3, widget_opts.css_min_height);
6712   lives_widget_set_sensitive(dsq->slider, TRUE);
6713   lives_range_set_range(LIVES_RANGE(dsq->slider), 0., 100.);
6714 
6715   hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6716   lives_layout_pack(LIVES_HBOX(hbox), dsq->slider);
6717 
6718   lives_widget_set_sensitive(dsq->slider, FALSE);
6719 
6720   dsq->sliderfunc = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(dsq->slider), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
6721                     LIVES_GUI_CALLBACK(qslider_changed), NULL);
6722 
6723   dsq->pculabel = lives_layout_add_label(LIVES_LAYOUT(layout), NULL, TRUE);
6724 
6725   if (prefs->startup_phase) add_fill_to_box(LIVES_BOX(dialog_vbox));
6726 
6727   if (!prefs->startup_phase) {
6728     add_hsep_to_box(LIVES_BOX(dialog_vbox));
6729 
6730     layout = lives_layout_new(LIVES_BOX(dialog_vbox));
6731 
6732     lives_layout_add_label(LIVES_LAYOUT(layout), _("Diskspace Management Options"), FALSE);
6733     lives_layout_add_fill(LIVES_LAYOUT(layout), FALSE);
6734 
6735     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
6736     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6737     widget_opts.expand = LIVES_EXPAND_DEFAULT;
6738 
6739     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6740     button = lives_standard_button_new_from_stock(LIVES_STOCK_PREFERENCES, _("Clean Up Diskspace"),
6741              DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6742     lives_widget_set_focus_on_click(button, FALSE);
6743     lives_box_pack_start(LIVES_BOX(hbox), button, FALSE, FALSE, widget_opts.packing_width * 4);
6744 
6745     lives_signal_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
6746                          LIVES_GUI_CALLBACK(cleards_cb), dialog);
6747 
6748     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6749     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6750 
6751     button = lives_standard_button_new_from_stock(LIVES_STOCK_PREFERENCES, _("Manage Clip Sets"),
6752              DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6753     lives_widget_set_focus_on_click(button, FALSE);
6754 
6755     lives_box_pack_start(LIVES_BOX(hbox), button, FALSE, FALSE, widget_opts.packing_width * 4);
6756 
6757     lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
6758                               LIVES_GUI_CALLBACK(manclips_cb),  dialog);
6759 
6760     if (mainw->num_sets == -1) {
6761       mainw->set_list = get_set_list(prefs->workdir, TRUE);
6762       if (mainw->set_list) {
6763         mainw->num_sets = lives_list_length(mainw->set_list);
6764         if (mainw->was_set) mainw->num_sets--;
6765       } else mainw->num_sets = 0;
6766     }
6767 
6768     if (mainw->num_sets <= 0) lives_widget_set_sensitive(button, FALSE);
6769 
6770     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6771     hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6772 
6773     button = lives_standard_button_new_from_stock(LIVES_STOCK_CLOSE, _("Close Current Clips"),
6774              DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
6775     lives_widget_set_focus_on_click(button, FALSE);
6776 
6777     //if (!mainw->clips_available) lives_widget_set_sensitive(button, FALSE);
6778     lives_widget_set_sensitive(button, FALSE); // TODO
6779 
6780     lives_box_pack_start(LIVES_BOX(hbox), button, FALSE, FALSE, widget_opts.packing_width * 4);
6781 
6782     widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
6783     lives_layout_add_fill(LIVES_LAYOUT(layout), TRUE);
6784     widget_opts.expand = LIVES_EXPAND_DEFAULT;
6785   }
6786   ////
6787 
6788   add_fill_to_box(LIVES_BOX(dialog_vbox));
6789 
6790   aar = LIVES_BOX(lives_dialog_get_action_area(LIVES_DIALOG(dialog)));
6791 
6792   rembutton =
6793     lives_standard_check_button_new(_("Show this dialog on startup"), prefs->show_disk_quota, aar,
6794                                     (tmp = lives_strdup(H_("These settings can also be changed "
6795                                         "in Preferences / Warnings"))));
6796 
6797   lives_signal_sync_connect(LIVES_GUI_OBJECT(rembutton), LIVES_WIDGET_TOGGLED_SIGNAL,
6798                             LIVES_GUI_CALLBACK(toggle_sets_pref), PREF_SHOW_QUOTA);
6799 
6800   lives_button_box_make_first(LIVES_BUTTON_BOX(aar), widget_opts.last_container);
6801 
6802   dsq->abort_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_QUIT,
6803                       _("Abort"), LIVES_RESPONSE_ABORT);
6804 
6805   lives_button_uncenter(dsq->abort_button, DLG_BUTTON_WIDTH * 2.);
6806 
6807   lives_signal_sync_connect(LIVES_GUI_OBJECT(dsq->abort_button), LIVES_WIDGET_CLICKED_SIGNAL,
6808                             LIVES_GUI_CALLBACK(dsu_abort_clicked),
6809                             prefsw ? prefsw->prefs_dialog : NULL);
6810   lives_widget_set_no_show_all(dsq->abort_button, TRUE);
6811 
6812   if (prefs->startup_phase)
6813     okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK,
6814                _("FINISH"), LIVES_RESPONSE_OK);
6815   else
6816     okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK,
6817                _("Continue with current values"), LIVES_RESPONSE_OK);
6818 
6819   lives_button_uncenter(okbutton, DLG_BUTTON_WIDTH * 2.);
6820 
6821   lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
6822                             LIVES_GUI_CALLBACK(dsu_ok_clicked),
6823                             prefsw ? prefsw->prefs_dialog : NULL);
6824 
6825   lives_button_grab_default_special(okbutton);
6826   lives_widget_grab_focus(okbutton);
6827 
6828   lives_widget_show_all(dialog);
6829 
6830   qslider_changed(dsq->slider, NULL);
6831 
6832   if (prefs->startup_phase) {
6833     char *wid = lives_strdup_printf("0x%08lx", (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(dialog)));
6834     if (!wid || !activate_x11_window(wid)) lives_window_set_keep_above(LIVES_WINDOW(dialog), TRUE);
6835     lives_dialog_run(LIVES_DIALOG(dialog));
6836   } else lives_idle_add_simple(update_dsu, NULL);
6837   if (mainw->cs_manage && mainw->num_sets) {
6838     mainw->cs_manage = FALSE;
6839     manclips_cb(NULL, dialog);
6840   } else mainw->cs_manage = FALSE;
6841 }
6842 
6843 
6844 //// message area functions
6845 //#define DEBUG_OVERFLOW
6846 
6847 static int vmin = -10000000;
6848 static int hmin = -10000000;
6849 static int reqheight = -1; // presumed height of msg_area
6850 static int reqwidth = -1; // presumed width of msg_area
6851 
6852 
get_screen_usable_size(int * w,int * h)6853 boolean get_screen_usable_size(int *w, int *h) {
6854   *w = GUI_SCREEN_WIDTH - ((hmin > 0) ? hmin : 0);
6855   *h = GUI_SCREEN_HEIGHT - ((vmin > 0) ? vmin : 0);
6856   if (vmin > 0 || hmin > 0) return TRUE;
6857   return FALSE;
6858 }
6859 
6860 
msg_area_scroll_to(LiVESWidget * widget,int msgno,boolean recompute,LiVESAdjustment * adj)6861 static boolean msg_area_scroll_to(LiVESWidget * widget, int msgno, boolean recompute, LiVESAdjustment * adj) {
6862   // "scroll" the message area so that the last message appears at the bottom
6863   LingoLayout *layout;
6864   lives_colRGBA64_t fg, bg;
6865 
6866   int width;
6867   int height = -1, lh;
6868   int nlines;
6869 
6870   static int last_height = -1;
6871 
6872   if (!prefs->show_msg_area) return FALSE;
6873   if (mainw->n_messages <= 0) return FALSE;
6874 
6875   if (!LIVES_IS_WIDGET(widget)) return FALSE;
6876 
6877   height = lives_widget_get_allocation_height(LIVES_WIDGET(widget));
6878   //if (reqheight != -1) height = reqheight;
6879   width = lives_widget_get_allocation_width(LIVES_WIDGET(widget));
6880   if (reqwidth != -1) width = reqwidth;
6881   //g_print("GET  LINGO xx %d %d\n", width, height);
6882 
6883   layout = (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout");
6884   if (layout) {
6885     if (LINGO_IS_LAYOUT(layout)) lingo_layout_set_text(layout, "", -1);
6886     lives_widget_object_unref(layout);
6887   }
6888   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), "layout", NULL);
6889 
6890   if (width < LAYOUT_SIZE_MIN || height < LAYOUT_SIZE_MIN) return FALSE;
6891 
6892   if (msgno < 0) msgno = 0;
6893   if (msgno >= mainw->n_messages) msgno = mainw->n_messages - 1;
6894 
6895   // redraw the layout ///////////////////////
6896   lives_widget_set_text_size(widget, LIVES_WIDGET_STATE_NORMAL, lives_textsize_to_string(prefs->msg_textsize));
6897 
6898   layout = layout_nth_message_at_bottom(msgno, width, height, LIVES_WIDGET(widget), &nlines);
6899   if (!LINGO_IS_LAYOUT(layout) || !layout) {
6900     return FALSE;
6901   }
6902 
6903   lingo_layout_get_size(layout, NULL, &lh);
6904   lh /= LINGO_SCALE;
6905   if (height != last_height) recompute = TRUE;
6906   last_height = height;
6907 
6908   if (recompute) {
6909     // redjust the page size
6910     if (nlines > 0) {
6911       double linesize = lh / nlines;
6912       double page_size = (double)((int)((double)height / linesize));
6913       //g_print("VALS3 lh = %d, nlines = %d, lsize = %f, height = %d, ps = %f\n", lh, nlines, linesize, height, page_size);
6914       lives_widget_object_freeze_notify(LIVES_WIDGET_OBJECT(adj));
6915       lives_adjustment_set_lower(adj, page_size);
6916       lives_adjustment_set_upper(adj, (double)(mainw->n_messages + page_size - 2));
6917       lives_adjustment_set_page_size(adj, page_size);
6918       lives_adjustment_set_value(adj, (double)msgno);
6919       lives_widget_object_thaw_notify(LIVES_WIDGET_OBJECT(adj));
6920       //g_print("PAGE SIZE is %f\n", page_size);
6921     }
6922   }
6923 
6924   widget_color_to_lives_rgba(&fg, &palette->info_text);
6925   widget_color_to_lives_rgba(&bg, &palette->info_base);
6926 
6927   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), "layout", layout);
6928   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), "layout_height", LIVES_INT_TO_POINTER(lh + .5));
6929   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), "layout_lines", LIVES_INT_TO_POINTER(nlines));
6930   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), "layout_last", LIVES_INT_TO_POINTER(msgno));
6931 
6932   return TRUE;
6933 }
6934 
6935 //#define DEBUG_OVERFLOW
6936 static int height, lheight;
6937 
msg_area_config(LiVESWidget * widget)6938 boolean msg_area_config(LiVESWidget * widget) {
6939   static int wiggle_room = 0;
6940   static int last_height = -1;
6941   static int last_textsize = -1;
6942 
6943   static int old_scr_width = -1;
6944   static int old_scr_height = -1;
6945 
6946   static int last_overflowy = 10000000;
6947   static int last_overflowx = 10000000;
6948 
6949   static int gui_posx = 1000000;
6950   static int gui_posy = 1000000;
6951 
6952   LingoLayout *layout;
6953   lives_rect_t rect;
6954 
6955   boolean mustret = FALSE;
6956 
6957   int width;
6958   int lineheight, llines, llast;
6959   int scr_width = GUI_SCREEN_WIDTH;
6960   int scr_height = mainw->mgeom[0].phys_height; //GUI_SCREEN_HEIGHT;
6961   int bx, by, w = -1, h = -1, posx, posy;
6962   int overflowx = 0, overflowy = 0, xoverflowx, xoverflowy;
6963   int ww, hh, vvmin, hhmin;
6964   int paisize = 0, opaisize;
6965 
6966   if (!mainw->is_ready) return FALSE;
6967   if (!prefs->show_msg_area) return FALSE;
6968   if (LIVES_IS_PLAYING && prefs->msgs_pbdis) return FALSE;
6969 
6970   if (mainw->multitrack && lives_widget_get_allocation_height(mainw->multitrack->top_vbox) < 32)
6971     return FALSE;
6972 
6973   lives_widget_set_vexpand(widget, TRUE);
6974 
6975   layout = (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout");
6976 
6977   if (last_textsize == -1) last_textsize = prefs->msg_textsize;
6978 
6979   width = lives_widget_get_allocation_width(widget);
6980   height = lives_widget_get_allocation_height(widget);
6981 
6982   if (reqwidth != -1) width = reqwidth;
6983   reqwidth = -1;
6984   if (reqheight != -1) height = reqheight;
6985   reqheight = -1;
6986 
6987   // the expose event for the message area is a good opportunity to recheck the window size
6988 
6989   //if (width < LAYOUT_SIZE_MIN || height < LAYOUT_SIZE_MIN) return FALSE;
6990 
6991   llast = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
6992                                "layout_last"));
6993 
6994   if (mainw->is_ready && (scr_width != old_scr_width || scr_height != old_scr_height)) {
6995     vmin = -10000000;
6996     hmin = -10000000;
6997     reqheight = -1; // presumed height of msg_area
6998     reqwidth = -1; // presumed width of msg_area
6999     wiggle_room = 0;
7000     last_height = -1;
7001     last_textsize = -1;
7002 
7003     last_overflowy = 10000000;
7004     last_overflowx = 10000000;
7005 
7006     old_scr_height = scr_height;
7007     old_scr_width = scr_width;
7008     gui_posx = gui_posy = 1000000;
7009   }
7010 
7011   lives_xwindow_get_frame_extents(lives_widget_get_xwindow(LIVES_MAIN_WINDOW_WIDGET), &rect);
7012 
7013   get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
7014 
7015   ww = lives_widget_get_allocation_width(LIVES_MAIN_WINDOW_WIDGET);
7016   w = mainw->assumed_width;
7017   if (w == -1) w = ww;
7018   hh = lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET);
7019   h = mainw->assumed_height;
7020   if (h == -1) h = hh;
7021 
7022   if (!mainw->multitrack) {
7023     overflowx = ww - (scr_width - bx);
7024     overflowy = hh - (scr_height - by);
7025 #ifdef DEBUG_OVERFLOW
7026     //g_print("ADJ A %d = %d - (%d - %d) + (%d - %d) %d %d\n", overflowy, h, scr_height, by, hh,
7027     // mainw->assumed_height, ABS(overflowy), vmin);
7028 #endif
7029     if (overflowx >= 0 && mainw->assumed_width != -1) {
7030       xoverflowx = ww - w;
7031       if (xoverflowx > overflowx) {
7032 #ifdef DEBUG_OVERFLOW
7033         g_print("ADJ B1 %d = %d - %d - %d\n", xoverflowx, rect.width, w, bx);
7034 #endif
7035         overflowx = xoverflowx;
7036       }
7037     }
7038 
7039     if (overflowy >= 0 && mainw->assumed_height != -1) {
7040       xoverflowy = hh - h;
7041       if (xoverflowy > overflowy) {
7042 #ifdef DEBUG_OVERFLOW
7043         g_print("ADJ B2 %d = %d - %d - %d\n", xoverflowy, rect.height, h, by);
7044 #endif
7045         overflowy = xoverflowy;
7046       }
7047     }
7048 
7049     if (ABS(overflowx) <= hmin) overflowx = 0;
7050     if (ABS(overflowy) <= vmin) overflowy = 0;
7051 
7052 #ifdef DEBUG_OVERFLOW
7053     g_print("overflow2 is %d : %d %d %d X %d : %d %d %d [%d %d %d]\n", overflowx, w, scr_width, bx, overflowy,
7054             h, scr_height, by, h,
7055             rect.height, lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET));
7056 #endif
7057 
7058     if (overflowx != 0 && w < scr_width && ww <= scr_width && overflowx == last_overflowx) {
7059       int xhmin = ABS(overflowx);
7060       if (xhmin < ABS(hmin)) {
7061         hmin = xhmin;
7062         mustret = TRUE;
7063       }
7064     }
7065     last_overflowx = overflowx;
7066 
7067 #ifdef DEBUG_OVERFLOW
7068     g_print("NOW %d %d %d %d %d\n", overflowy, h, scr_height, hh, last_overflowy);
7069 #endif
7070     if (overflowy != 0 && h <= scr_height && hh <= scr_height && overflowy == last_overflowy) {
7071       int xvmin = ABS(overflowy);
7072       if (xvmin < ABS(vmin)) {
7073         vmin = xvmin;
7074         mustret = TRUE;
7075       }
7076     }
7077     last_overflowy = overflowy;
7078 
7079 #ifdef DEBUG_OVERFLOW
7080     g_print("WIDG SIZE %d X %d, %d,%d and %d %d %d\n", width, height, hmin, vmin, bx, by, mustret);
7081 #endif
7082     vvmin = by - vmin;
7083     if (vvmin < by && by - vmin < vmin) vmin = by - vmin;
7084 
7085     hhmin = bx - hmin;
7086     if (hhmin < bx && bx - hmin < hmin) hmin = bx - hmin;
7087 
7088     if (mustret) {
7089       lives_widget_queue_draw(mainw->msg_area);
7090       return FALSE;
7091     }
7092   }
7093 
7094   if (overflowx != 0 || overflowy != 0) {
7095 #ifdef DEBUG_OVERFLOW
7096     g_print("overflow is %d X %d : %d %d\n", overflowx, overflowy, width, height);
7097 #endif
7098     width -= overflowx;
7099     height -= overflowy;
7100 
7101     if (!mainw->multitrack) {
7102       if (height <= MIN_MSGBAR_HEIGHT) {
7103         height = MIN_MSGBAR_HEIGHT;
7104         mainw->mbar_res = height;
7105         if (!LIVES_IS_PLAYING && CURRENT_CLIP_IS_VALID) redraw_timeline(mainw->current_file);
7106       }
7107 
7108       if (width < 0 || height < 0) return FALSE;
7109     }
7110 
7111     w -= overflowx;
7112     h -= overflowy;
7113 
7114     if (!prefs->open_maximised) {
7115       mainw->assumed_width = w;
7116       mainw->assumed_height = h;
7117       lives_window_resize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), w, h);
7118       lives_xwindow_get_origin(lives_widget_get_xwindow(LIVES_MAIN_WINDOW_WIDGET), &posx, &posy);
7119 #ifdef DEBUG_OVERFLOW
7120       g_print("2MOVE to %d X %d\n", posx, posy);
7121 #endif
7122     } else {
7123       mainw->assumed_width = rect.width - overflowx - bx;
7124       mainw->assumed_height = rect.height - overflowy - by;
7125     }
7126 
7127     if (!prefs->open_maximised) {
7128       if (overflowx > 0) posx -= overflowx;
7129       else posx = -overflowx;
7130       if (posx < 0) posx = 0;
7131       if (overflowy > 0) posy = overflowy - posy;
7132       if (posy < 0) posy = 0;
7133 
7134       if (posx > gui_posx) posx = gui_posx;
7135       if (posy > gui_posy) posy = gui_posy;
7136 
7137 #ifdef DEBUG_OVERFLOW
7138       g_print("MOVE to %d X %d\n", posx, posy);
7139 #endif
7140       lives_window_move(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), posx, posy);
7141 
7142       gui_posx = posx;
7143       gui_posy = posy;
7144     }
7145 
7146     if (height > 0 && width > 0) {
7147       if (mainw->multitrack) {
7148         if (height <= MIN_MSGBAR_HEIGHT) {
7149           int pos = lives_paned_get_position(LIVES_PANED(mainw->multitrack->top_vpaned));
7150           pos = pos + height - MIN_MSGBAR_HEIGHT;
7151           height = MIN_MSGBAR_HEIGHT;
7152           lives_container_child_set_shrinkable(LIVES_CONTAINER(mainw->multitrack->top_vpaned),
7153                                                mainw->multitrack->vpaned, FALSE);
7154           lives_paned_set_position(LIVES_PANED(mainw->multitrack->top_vpaned), pos);
7155         } else
7156           lives_container_child_set_shrinkable(LIVES_CONTAINER(mainw->multitrack->top_vpaned),
7157                                                mainw->multitrack->vpaned, TRUE);
7158       } else {
7159         if (mainw->mbar_res && height >= mainw->mbar_res * 2) {
7160           mainw->mbar_res = 0;
7161           height -= mainw->mbar_res;
7162         }
7163       }
7164 
7165       lives_widget_set_size_request(widget, width, height);
7166       reqwidth = width;
7167       reqheight = height;
7168     }
7169 
7170     if (prefs->show_msg_area) lives_widget_show_all(mainw->message_box);
7171 
7172     if (!prefs->open_maximised)
7173       lives_window_move(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), posx, posy);
7174     else
7175       lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
7176   }
7177 
7178   opaisize = paisize;
7179   paisize = lives_widget_get_allocation_width(lives_widget_get_parent(widget));
7180 
7181   if (!layout || !LINGO_IS_LAYOUT(layout) || paisize != opaisize) {
7182     // this can happen e.g if we open the app. with no clips
7183     msg_area_scroll_to_end(widget, mainw->msg_adj);
7184 
7185     // reget this as it may have changed
7186     layout = (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout");
7187     if (!layout || !LINGO_IS_LAYOUT(layout)) {
7188       return FALSE;
7189     }
7190   }
7191 
7192   if (!prefs->open_maximised && !mainw->multitrack && gui_posx < 1000000)
7193     lives_window_move(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), gui_posx, gui_posy);
7194 
7195   gui_posx = gui_posy = 1000000;
7196 
7197   // check if we could request more
7198   lheight = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout_height"));
7199   if (lheight == 0) return FALSE;
7200 
7201   if (height != last_height) wiggle_room = 0;
7202   last_height = height;
7203 
7204 #ifdef DEBUG_OVERFLOW
7205   g_print("VALS %d, %d %d\n", lheight, height, wiggle_room);
7206 #endif
7207 
7208   llines = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout_lines"));
7209   lineheight = CEIL(lheight / llines, 1);
7210 
7211   if (height / lineheight < MIN_MSGBOX_LLINES) {
7212     /// try a smaller font size if we can
7213     if (prefs->msg_textsize > 1) prefs->msg_textsize--;
7214     else if (height < lineheight) return FALSE;
7215     mainw->max_textsize = prefs->msg_textsize;
7216   }
7217 
7218   if (lheight < height - wiggle_room || prefs->msg_textsize != last_textsize) {
7219 #ifdef DEBUG_OVERFLOW
7220     g_print("VALS2 %d %d %d : %d %d\n", height / lineheight, llines + 1, llast, prefs->msg_textsize, last_textsize);
7221 #endif
7222     if ((height / lineheight >= llines + 1 && llast > llines) || (prefs->msg_textsize != last_textsize)) {
7223 #ifdef DEBUG_OVERFLOW
7224       g_print("VALS22 %d %d %d : %d %d\n", height / lineheight, llines + 1, llast, prefs->msg_textsize, last_textsize);
7225 #endif
7226       // recompute if the window grew or the text size changed
7227       last_textsize = prefs->msg_textsize;
7228       msg_area_scroll_to(widget, llast, TRUE, mainw->msg_adj); // window grew, re-get layout
7229       layout = (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout");
7230       if (!layout || !LINGO_IS_LAYOUT(layout)) {
7231         return FALSE;
7232       }
7233       lheight = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
7234                                      "layout_height"));
7235       wiggle_room = height - lheight;
7236     }
7237   }
7238   return FALSE;
7239 }
7240 
7241 
reshow_msg_area(LiVESWidget * widget,lives_painter_t * cr,livespointer psurf)7242 boolean reshow_msg_area(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
7243   lives_painter_t *cr2;
7244   LingoLayout *layout;
7245   LiVESWidgetState state = lives_widget_get_state(widget);
7246 
7247   if (!prefs->show_msg_area) return TRUE;
7248 
7249   if (state & LIVES_WIDGET_STATE_BACKDROP) return TRUE;
7250 
7251   layout = (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), "layout");
7252 
7253   if (layout && LINGO_IS_LAYOUT(layout)) {
7254     lives_colRGBA64_t fg, bg;
7255     int rwidth = lives_widget_get_allocation_width(widget);
7256     int rheight = lives_widget_get_allocation_height(widget);
7257 
7258     widget_color_to_lives_rgba(&fg, &palette->info_text);
7259     widget_color_to_lives_rgba(&bg, &palette->info_base);
7260 
7261     cr2 = lives_painter_create_from_surface(mainw->msg_surface);
7262     lives_painter_render_background(widget, cr2, 0., 0., rwidth, rheight);
7263 
7264     height = lives_widget_get_allocation_height(widget);
7265 
7266     layout_to_lives_painter(layout, cr2, LIVES_TEXT_MODE_FOREGROUND_AND_BACKGROUND, &fg, &bg, rwidth, rheight,
7267                             0., 0., 0., height - lheight - 4);
7268     lingo_painter_show_layout(cr2, layout);
7269     lives_painter_destroy(cr2);
7270   }
7271   lives_painter_set_source_surface(cr, mainw->msg_surface, 0., 0.);
7272   lives_painter_paint(cr);
7273   return FALSE;
7274 }
7275 
7276 
msg_area_scroll_to_end(LiVESWidget * widget,LiVESAdjustment * adj)7277 LIVES_GLOBAL_INLINE void msg_area_scroll_to_end(LiVESWidget * widget, LiVESAdjustment * adj) {
7278   if (!prefs->show_msg_area) return;
7279   msg_area_scroll_to(widget, mainw->n_messages - 2, TRUE, adj);
7280   // expose_msg_area(widget, NULL, NULL);
7281 }
7282 
7283 
msg_area_scroll(LiVESAdjustment * adj,livespointer userdata)7284 void msg_area_scroll(LiVESAdjustment * adj, livespointer userdata) {
7285   // scrollbar callback
7286   LiVESWidget *widget = (LiVESWidget *)userdata;
7287   double val;
7288   if (!prefs->show_msg_area) return;
7289   if (!LIVES_IS_ADJUSTMENT(adj)) return;
7290   val = lives_adjustment_get_value(adj);
7291   //g_print("val is %f rnd %d\n", val, (int)(val + .5));
7292   if (msg_area_scroll_to(widget, (int)(val + .5), FALSE, adj))
7293     lives_widget_queue_draw(widget);
7294   //reshow_msg_area(widget);
7295 }
7296 
7297 
on_msg_area_scroll(LiVESWidget * widget,LiVESXEventScroll * event,livespointer user_data)7298 boolean on_msg_area_scroll(LiVESWidget * widget, LiVESXEventScroll * event, livespointer user_data) {
7299   // mouse scroll callback
7300   LiVESAdjustment *adj = (LiVESAdjustment *)user_data;
7301   if (lives_get_scroll_direction(event) == LIVES_SCROLL_UP) lives_adjustment_set_value(adj, lives_adjustment_get_value(adj) - 1.);
7302   if (lives_get_scroll_direction(event) == LIVES_SCROLL_DOWN) lives_adjustment_set_value(adj,
7303         lives_adjustment_get_value(adj) + 1.);
7304   return FALSE;
7305 }
7306