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