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