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