fix dangling thread svg, reduce mute patch
[goodguy/history.git] / cinelerra-5.1 / cinelerra / patchgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "automation.h"
23 #include "bcsignals.h"
24 #include "cplayback.h"
25 #include "cwindow.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "intauto.h"
29 #include "intautos.h"
30 #include "language.h"
31 #include "localsession.h"
32 #include "mainsession.h"
33 #include "mainundo.h"
34 #include "mwindow.h"
35 #include "mwindowgui.h"
36 #include "patchbay.h"
37 #include "patchgui.h"
38 #include "playbackengine.h"
39 #include "theme.h"
40 #include "track.h"
41 #include "trackcanvas.h"
42 #include "tracks.h"
43 #include "transportque.h"
44 #include "vframe.h"
45
46
47
48 PatchGUI::PatchGUI(MWindow *mwindow,
49                 PatchBay *patchbay,
50                 Track *track,
51                 int x,
52                 int y)
53 {
54         this->mwindow = mwindow;
55         this->patchbay = patchbay;
56         this->track = track;
57         this->x = x;
58         this->y = y;
59         title = 0;
60         record = 0;
61         play = 0;
62 //      automate = 0;
63         gang = 0;
64         draw = 0;
65         mute = 0;
66         expand = 0;
67         nudge = 0;
68         change_source = 0;
69         track_id = -1;
70         if(track) track_id = track->get_id();
71 }
72
73 PatchGUI::~PatchGUI()
74 {
75         if(title) delete title;
76         if(record) delete record;
77         if(play) delete play;
78 //      if(automate) delete automate;
79         if(gang) delete gang;
80         if(draw) delete draw;
81         if(mute) delete mute;
82         if(expand) delete expand;
83         if(nudge) delete nudge;
84 }
85
86 void PatchGUI::create_objects()
87 {
88         update(x, y);
89 }
90
91 int PatchGUI::reposition(int x, int y)
92 {
93         int x1 = 0;
94         int y1 = 0;
95
96
97         if(x != this->x || y != this->y)
98         {
99                 this->x = x;
100                 this->y = y;
101
102                 if(title)
103                 {
104 TRACE("PatchGUI::reposition 1\n");
105                         title->reposition_window(title->get_x(), y1 + y, 0);
106 TRACE("PatchGUI::reposition 2\n");
107                 }
108                 y1 += mwindow->theme->title_h;
109
110                 if(play)
111                 {
112 TRACE("PatchGUI::reposition 3\n");
113                         play->reposition_window(play->get_x(), y1 + y);
114                         x1 += play->get_w();
115 TRACE("PatchGUI::reposition 4\n");
116                         record->reposition_window(record->get_x(), y1 + y);
117                         x1 += record->get_w();
118 TRACE("PatchGUI::reposition 5\n");
119 //                      automate->reposition_window(x1, y1 + y);
120 //                      x1 += automate->get_w();
121                         gang->reposition_window(gang->get_x(), y1 + y);
122                         x1 += gang->get_w();
123 TRACE("PatchGUI::reposition 6\n");
124                         draw->reposition_window(draw->get_x(), y1 + y);
125                         x1 += draw->get_w();
126 TRACE("PatchGUI::reposition 7\n");
127                         mute->reposition_window(mute->get_x(), y1 + y);
128                         x1 += mute->get_w();
129 TRACE("PatchGUI::reposition 8\n");
130
131                         if(expand)
132                         {
133 TRACE("PatchGUI::reposition 9\n");
134 //      VFrame **expandpatch_data = mwindow->theme->get_image_set("expandpatch_data");
135 //      int x = patchbay->get_w() - 10 - expandpatch_data[0]->get_w();
136                                 expand->reposition_window(
137                                         expand->get_x(),
138                                         y1 + y);
139 TRACE("PatchGUI::reposition 10\n");
140                                 x1 += expand->get_w();
141 TRACE("PatchGUI::reposition 11\n");
142                         }
143                 }
144                 y1 += mwindow->theme->play_h;
145         }
146         else
147         {
148                 y1 += mwindow->theme->title_h;
149                 y1 += mwindow->theme->play_h;
150         }
151
152         return y1;
153 }
154
155 int PatchGUI::update(int x, int y)
156 {
157 //TRACE("PatchGUI::update 1");
158         reposition(x, y);
159 //TRACE("PatchGUI::update 10");
160
161         int h = track->vertical_span(mwindow->theme);
162         int y1 = 0;
163         int x1 = 0;
164 //printf("PatchGUI::update 10\n");
165
166         if(title)
167         {
168                 if(h - y1 < 0)
169                 {
170                         delete title;
171                         title = 0;
172                 }
173                 else
174                 {
175                         title->update(track->title);
176                 }
177         }
178         else
179         if(h - y1 >= 0)
180         {
181                 patchbay->add_subwindow(title = new TitlePatch(mwindow, this, x1 + x, y1 + y));
182         }
183         y1 += mwindow->theme->title_h;
184
185         if(play)
186         {
187                 if(h - y1 < mwindow->theme->play_h)
188                 {
189                         delete play;    play = 0;
190                         delete record;  record = 0;
191                         delete gang;    gang = 0;
192                         delete draw;    draw = 0;
193                         delete mute;    mute = 0;
194                         delete expand;  expand = 0;
195                 }
196                 else
197                 {
198                         play->update(track->play);
199                         record->update(track->record);
200                         gang->update(track->gang);
201                         draw->update(track->draw);
202                         mute->update(mute->get_keyframe(mwindow, this)->value);
203                         expand->update(track->expand_view);
204                 }
205         }
206         else
207         if(h - y1 >= mwindow->theme->play_h)
208         {
209                 patchbay->add_subwindow(play = new PlayPatch(mwindow, this, x1 + x, y1 + y));
210 //printf("PatchGUI::update %d %d\n", __LINE__, play->get_h());
211                 x1 += play->get_w();
212                 patchbay->add_subwindow(record = new RecordPatch(mwindow, this, x1 + x, y1 + y));
213                 x1 += record->get_w();
214                 patchbay->add_subwindow(gang = new GangPatch(mwindow, this, x1 + x, y1 + y));
215                 x1 += gang->get_w();
216                 patchbay->add_subwindow(draw = new DrawPatch(mwindow, this, x1 + x, y1 + y));
217                 x1 += draw->get_w();
218                 patchbay->add_subwindow(mute = new MutePatch(mwindow, this, x1 + x, y1 + y));
219                 x1 += mute->get_w();
220
221                 VFrame **expandpatch_data = mwindow->theme->get_image_set("expandpatch_data");
222                 patchbay->add_subwindow(expand = new ExpandPatch(mwindow,
223                         this,
224                         patchbay->get_w() - 10 - expandpatch_data[0]->get_w(),
225                         y1 + y));
226                 x1 += expand->get_w();
227         }
228         y1 += mwindow->theme->play_h;
229
230 //UNTRACE
231         return y1;
232 }
233
234
235 void PatchGUI::toggle_behavior(int type,
236                 int value,
237                 BC_Toggle *toggle,
238                 int *output)
239 {
240         if(toggle->shift_down()) {
241                 int sense = type != Tracks::MUTE ? 1 : 0;
242                 // all selected if nothing previously selected or
243                 // if this patch was previously the only one selected
244                 int total_type = mwindow->edl->tracks->total_of(type);
245                 int total_selected = sense ? total_type :
246                         mwindow->edl->tracks->total() - total_type;
247                 int selected = !total_selected || (total_selected == 1 &&
248                          *output == sense ) ? sense : 1-sense;
249                 mwindow->edl->tracks->select_all(type, selected);
250                 if( selected != sense ) *output = sense;
251
252                 patchbay->drag_operation = type;
253                 patchbay->new_status = 1;
254         }
255         else
256         {
257                 *output = value;
258 // Select + drag behavior
259                 patchbay->drag_operation = type;
260                 patchbay->new_status = value;
261         }
262
263         switch(type)
264         {
265                 case Tracks::PLAY:
266                         mwindow->gui->unlock_window();
267                         mwindow->restart_brender();
268                         mwindow->sync_parameters(CHANGE_EDL);
269                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 1");
270                         break;
271
272                 case Tracks::MUTE:
273                         mwindow->gui->unlock_window();
274                         mwindow->restart_brender();
275                         mwindow->sync_parameters(CHANGE_PARAMS);
276                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 2");
277                         break;
278
279 // Update affected tracks in cwindow
280                 case Tracks::RECORD:
281                         mwindow->cwindow->update(0, 1, 1);
282                         break;
283
284                 case Tracks::GANG:
285                         break;
286
287                 case Tracks::DRAW:
288                         mwindow->gui->update(0, 1, 0, 0, 0, 0, 0);
289                         break;
290
291                 case Tracks::EXPAND:
292                         break;
293         }
294
295 // update all panes
296         mwindow->gui->update_patchbay();
297 }
298
299
300 char* PatchGUI::calculate_nudge_text(int *changed)
301 {
302         if(changed) *changed = 0;
303         if(track->edl->session->nudge_format)
304         {
305                 sprintf(string_return, "%.4f", track->from_units(track->nudge));
306                 if(changed && nudge && atof(nudge->get_text()) - atof(string_return) != 0)
307                         *changed = 1;
308         }
309         else
310         {
311                 sprintf(string_return, "%jd", track->nudge);
312                 if(changed && nudge && atoi(nudge->get_text()) - atoi(string_return) != 0)
313                         *changed = 1;
314         }
315         return string_return;
316 }
317
318
319 int64_t PatchGUI::calculate_nudge(const char *string)
320 {
321         if(mwindow->edl->session->nudge_format)
322         {
323                 float result;
324                 sscanf(string, "%f", &result);
325                 return track->to_units(result, 0);
326         }
327         else
328         {
329                 int64_t temp;
330                 sscanf(string, "%jd", &temp);
331                 return temp;
332         }
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346 PlayPatch::PlayPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
347  : BC_Toggle(x,
348                 y,
349                 mwindow->theme->get_image_set("playpatch_data"),
350                 patch->track->play,
351                 "",
352                 0,
353                 0,
354                 0)
355 {
356         this->mwindow = mwindow;
357         this->patch = patch;
358         set_tooltip(_("Play track"));
359         set_select_drag(1);
360 }
361
362 int PlayPatch::button_press_event()
363 {
364         if(is_event_win() && get_buttonpress() == 1)
365         {
366                 mwindow->undo->update_undo_before();
367                 set_status(BC_Toggle::TOGGLE_DOWN);
368                 update(!get_value());
369                 patch->toggle_behavior(Tracks::PLAY,
370                         get_value(),
371                         this,
372                         &patch->track->play);
373                 return 1;
374         }
375         return 0;
376 }
377
378 int PlayPatch::button_release_event()
379 {
380         int result = BC_Toggle::button_release_event();
381         if(patch->patchbay->drag_operation == Tracks::PLAY)
382         {
383                 mwindow->undo->update_undo_after(_("play patch"), LOAD_PATCHES);
384                 patch->patchbay->drag_operation = Tracks::NONE;
385         }
386         return result;
387 }
388
389
390
391
392
393
394
395
396
397
398
399 RecordPatch::RecordPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
400  : BC_Toggle(x,
401                 y,
402                 mwindow->theme->get_image_set("recordpatch_data"),
403                 patch->track->record,
404                 "",
405                 0,
406                 0,
407                 0)
408 {
409         this->mwindow = mwindow;
410         this->patch = patch;
411         set_tooltip(_("Arm track"));
412         set_select_drag(1);
413 }
414
415 int RecordPatch::button_press_event()
416 {
417         if(is_event_win() && get_buttonpress() == 1)
418         {
419                 mwindow->undo->update_undo_before();
420                 set_status(BC_Toggle::TOGGLE_DOWN);
421                 update(!get_value());
422                 patch->toggle_behavior(Tracks::RECORD,
423                         get_value(),
424                         this,
425                         &patch->track->record);
426                 return 1;
427         }
428         return 0;
429 }
430
431 int RecordPatch::button_release_event()
432 {
433         int result = BC_Toggle::button_release_event();
434         if(patch->patchbay->drag_operation == Tracks::RECORD)
435         {
436                 mwindow->undo->update_undo_after(_("record patch"), LOAD_PATCHES);
437                 patch->patchbay->drag_operation = Tracks::NONE;
438         }
439         return result;
440 }
441
442
443
444
445
446
447
448
449
450
451
452 GangPatch::GangPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
453  : BC_Toggle(x, y,
454                 mwindow->theme->get_image_set("gangpatch_data"),
455                 patch->track->gang,
456                 "",
457                 0,
458                 0,
459                 0)
460 {
461         this->mwindow = mwindow;
462         this->patch = patch;
463         set_tooltip(_("Gang faders"));
464         set_select_drag(1);
465 }
466
467 int GangPatch::button_press_event()
468 {
469         if(is_event_win() && get_buttonpress() == 1)
470         {
471                 mwindow->undo->update_undo_before();
472                 set_status(BC_Toggle::TOGGLE_DOWN);
473                 update(!get_value());
474                 patch->toggle_behavior(Tracks::GANG,
475                         get_value(),
476                         this,
477                         &patch->track->gang);
478                 return 1;
479         }
480         return 0;
481 }
482
483 int GangPatch::button_release_event()
484 {
485         int result = BC_Toggle::button_release_event();
486         if(patch->patchbay->drag_operation == Tracks::GANG)
487         {
488                 mwindow->undo->update_undo_after(_("gang patch"), LOAD_PATCHES);
489                 patch->patchbay->drag_operation = Tracks::NONE;
490         }
491         return result;
492 }
493
494
495
496
497
498
499
500
501
502
503
504 DrawPatch::DrawPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
505  : BC_Toggle(x, y,
506                 mwindow->theme->get_image_set("drawpatch_data"),
507                 patch->track->draw,
508                 "",
509                 0,
510                 0,
511                 0)
512 {
513         this->mwindow = mwindow;
514         this->patch = patch;
515         set_tooltip(_("Draw media"));
516         set_select_drag(1);
517 }
518
519 int DrawPatch::button_press_event()
520 {
521         if(is_event_win() && get_buttonpress() == 1)
522         {
523                 mwindow->undo->update_undo_before();
524                 set_status(BC_Toggle::TOGGLE_DOWN);
525                 update(!get_value());
526                 patch->toggle_behavior(Tracks::DRAW,
527                         get_value(),
528                         this,
529                         &patch->track->draw);
530                 return 1;
531         }
532         return 0;
533 }
534
535 int DrawPatch::button_release_event()
536 {
537         int result = BC_Toggle::button_release_event();
538         if(patch->patchbay->drag_operation == Tracks::DRAW)
539         {
540                 mwindow->undo->update_undo_after(_("draw patch"), LOAD_PATCHES);
541                 patch->patchbay->drag_operation = Tracks::NONE;
542         }
543         return result;
544 }
545
546
547
548
549
550
551
552
553
554
555 MutePatch::MutePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
556  : BC_Toggle(x, y,
557                 mwindow->theme->get_image_set("mutepatch_data"),
558                 get_keyframe(mwindow, patch)->value,
559                 "",
560                 0,
561                 0,
562                 0)
563 {
564         this->mwindow = mwindow;
565         this->patch = patch;
566         set_tooltip(_("Don't send to output"));
567         set_select_drag(1);
568 }
569
570 int MutePatch::button_press_event()
571 {
572         if(is_event_win() && get_buttonpress() == 1)
573         {
574                 mwindow->undo->update_undo_before();
575                 set_status(BC_Toggle::TOGGLE_DOWN);
576                 update(!get_value());
577                 IntAuto *current;
578                 double position = mwindow->edl->local_session->get_selectionstart(1);
579                 Autos *mute_autos = patch->track->automation->autos[AUTOMATION_MUTE];
580
581
582                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
583                 current->value = get_value();
584
585                 patch->toggle_behavior(Tracks::MUTE,
586                         get_value(),
587                         this,
588                         &current->value);
589
590
591
592                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
593                 {
594                         mwindow->gui->draw_overlays(1);
595                 }
596                 return 1;
597         }
598         return 0;
599 }
600
601 int MutePatch::button_release_event()
602 {
603         int result = BC_Toggle::button_release_event();
604         if(patch->patchbay->drag_operation == Tracks::MUTE)
605         {
606                 mwindow->undo->update_undo_after(_("mute patch"), LOAD_PATCHES);
607                 patch->patchbay->drag_operation = Tracks::NONE;
608         }
609         return result;
610 }
611
612 IntAuto* MutePatch::get_keyframe(MWindow *mwindow, PatchGUI *patch)
613 {
614         Auto *current = 0;
615         double unit_position = mwindow->edl->local_session->get_selectionstart(1);
616         unit_position = mwindow->edl->align_to_frame(unit_position, 0);
617         unit_position = patch->track->to_units(unit_position, 0);
618         return (IntAuto*)patch->track->automation->autos[AUTOMATION_MUTE]->get_prev_auto(
619                 (int64_t)unit_position,
620                 PLAY_FORWARD,
621                 current);
622 }
623
624
625
626
627
628
629
630
631
632
633
634
635 ExpandPatch::ExpandPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
636  : BC_Toggle(x,
637                 y,
638                 mwindow->theme->get_image_set("expandpatch_data"),
639                 patch->track->expand_view,
640                 "",
641                 0,
642                 0,
643                 0)
644 {
645         this->mwindow = mwindow;
646         this->patch = patch;
647         set_select_drag(1);
648 }
649
650 int ExpandPatch::button_press_event()
651 {
652         if(is_event_win() && get_buttonpress() == 1)
653         {
654                 mwindow->undo->update_undo_before();
655                 set_status(BC_Toggle::TOGGLE_DOWN);
656                 update(!get_value());
657                 patch->toggle_behavior(Tracks::EXPAND,
658                         get_value(),
659                         this,
660                         &patch->track->expand_view);
661                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
662                 mwindow->gui->draw_trackmovement();
663                 return 1;
664         }
665         return 0;
666 }
667
668 int ExpandPatch::button_release_event()
669 {
670         int result = BC_Toggle::button_release_event();
671         if(patch->patchbay->drag_operation == Tracks::EXPAND)
672         {
673                 mwindow->undo->update_undo_after(_("expand patch"), LOAD_PATCHES);
674                 patch->patchbay->drag_operation = Tracks::NONE;
675         }
676         return result;
677 }
678
679
680
681
682
683 TitlePatch::TitlePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
684  : BC_TextBox(x,
685                 y,
686                 patch->patchbay->get_w() - 10,
687                 1,
688                 patch->track->title,
689                 1, MEDIUMFONT, 1)
690 {
691         this->mwindow = mwindow;
692         this->patch = patch;
693 }
694
695 int TitlePatch::handle_event()
696 {
697         mwindow->undo->update_undo_before(_("track title"), this);
698         strcpy(patch->track->title, get_text());
699         mwindow->update_plugin_titles();
700         mwindow->gui->draw_overlays(1);
701         mwindow->undo->update_undo_after(_("track title"), LOAD_PATCHES);
702         return 1;
703 }
704
705
706
707
708
709
710
711
712
713 NudgePatch::NudgePatch(MWindow *mwindow,
714         PatchGUI *patch,
715         int x,
716         int y,
717         int w)
718  : BC_TextBox(x,
719         y,
720         w,
721         1,
722         patch->calculate_nudge_text(0))
723 {
724         this->mwindow = mwindow;
725         this->patch = patch;
726         set_tooltip(_("Nudge"));
727 }
728
729 int NudgePatch::handle_event()
730 {
731         set_value(patch->calculate_nudge(get_text()));
732         return 1;
733 }
734
735 void NudgePatch::set_value(int64_t value)
736 {
737         mwindow->undo->update_undo_before(_("nudge"), this);
738         patch->track->nudge = value;
739
740         if(patch->track->gang && patch->track->record)
741                 patch->patchbay->synchronize_nudge(patch->track->nudge, patch->track);
742
743         mwindow->undo->update_undo_after(_("nudge"), LOAD_PATCHES);
744
745         mwindow->gui->unlock_window();
746         if(patch->track->data_type == TRACK_VIDEO)
747                 mwindow->restart_brender();
748         mwindow->sync_parameters(CHANGE_PARAMS);
749         mwindow->gui->lock_window("NudgePatch::handle_event 2");
750
751         mwindow->session->changes_made = 1;
752 }
753
754
755 int NudgePatch::button_press_event()
756 {
757         int result = 0;
758
759         if(is_event_win() && cursor_inside())
760         {
761                 if(get_buttonpress() == 4)
762                 {
763                         int value = patch->calculate_nudge(get_text());
764                         value += calculate_increment();
765                         set_value(value);
766                         update();
767                         result = 1;
768                 }
769                 else
770                 if(get_buttonpress() == 5)
771                 {
772                         int value = patch->calculate_nudge(get_text());
773                         value -= calculate_increment();
774                         set_value(value);
775                         update();
776                         result = 1;
777                 }
778                 else
779                 if(get_buttonpress() == 3)
780                 {
781                         patch->patchbay->nudge_popup->activate_menu(patch);
782                         result = 1;
783                 }
784         }
785
786         if(!result)
787                 return BC_TextBox::button_press_event();
788         else
789                 return result;
790 }
791
792 int64_t NudgePatch::calculate_increment()
793 {
794         if(patch->track->data_type == TRACK_AUDIO)
795         {
796                 return (int64_t)ceil(patch->track->edl->session->sample_rate / 10.0);
797         }
798         else
799         {
800                 return (int64_t)ceil(1.0 / patch->track->edl->session->frame_rate);
801         }
802 }
803
804 void NudgePatch::update()
805 {
806         int changed;
807         char *string = patch->calculate_nudge_text(&changed);
808         if(changed)
809                 BC_TextBox::update(string);
810 }
811
812
813
814