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