r863: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / patchgui.C
blob665b5217cf110dceda0b37380dc1be47d6525661
1 #include "automation.h"
2 #include "bcsignals.h"
3 #include "cplayback.h"
4 #include "cwindow.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "intauto.h"
8 #include "intautos.h"
9 #include "language.h"
10 #include "localsession.h"
11 #include "mainsession.h"
12 #include "mainundo.h"
13 #include "mwindow.h"
14 #include "mwindowgui.h"
15 #include "patchbay.h"
16 #include "patchgui.h"
17 #include "playbackengine.h"
18 #include "theme.h"
19 #include "track.h"
20 #include "trackcanvas.h"
21 #include "tracks.h"
22 #include "transportque.h"
23 #include "vframe.h"
27 PatchGUI::PatchGUI(MWindow *mwindow, 
28                 PatchBay *patchbay, 
29                 Track *track, 
30                 int x, 
31                 int y)
33         this->mwindow = mwindow;
34         this->patchbay = patchbay;
35         this->track = track;
36         this->x = x;
37         this->y = y;
38         title = 0;
39         record = 0;
40         play = 0;
41 //      automate = 0;
42         gang = 0;
43         draw = 0;
44         mute = 0;
45         expand = 0;
46         nudge = 0;
47         change_source = 0;
48         track_id = -1;
49         if(track) track_id = track->get_id();
52 PatchGUI::~PatchGUI()
54         if(title) delete title;
55         if(record) delete record;
56         if(play) delete play;
57 //      if(automate) delete automate;
58         if(gang) delete gang;
59         if(draw) delete draw;
60         if(mute) delete mute;
61         if(expand) delete expand;
62         if(nudge) delete nudge;
65 int PatchGUI::create_objects()
67         return update(x, y);
70 int PatchGUI::reposition(int x, int y)
72         int x1 = 0;
73         int y1 = 0;
76         if(x != this->x || y != this->y)
77         {
78                 this->x = x;
79                 this->y = y;
81                 if(title)
82                 {
83 TRACE("PatchGUI::reposition 1\n");
84                         title->reposition_window(x1, y1 + y);
85 TRACE("PatchGUI::reposition 2\n");
86                 }
87                 y1 += mwindow->theme->title_h;
89                 if(play)
90                 {
91 TRACE("PatchGUI::reposition 3\n");
92                         play->reposition_window(x1, y1 + y);
93                         x1 += play->get_w();
94 TRACE("PatchGUI::reposition 4\n");
95                         record->reposition_window(x1, y1 + y);
96                         x1 += record->get_w();
97 TRACE("PatchGUI::reposition 5\n");
98 //                      automate->reposition_window(x1, y1 + y);
99 //                      x1 += automate->get_w();
100                         gang->reposition_window(x1, y1 + y);
101                         x1 += gang->get_w();
102 TRACE("PatchGUI::reposition 6\n");
103                         draw->reposition_window(x1, y1 + y);
104                         x1 += draw->get_w();
105 TRACE("PatchGUI::reposition 7\n");
106                         mute->reposition_window(x1, y1 + y);
107                         x1 += mute->get_w();
108 TRACE("PatchGUI::reposition 8\n");
110                         if(expand)
111                         {
112 TRACE("PatchGUI::reposition 9\n");
113                                 VFrame **expandpatch_data = mwindow->theme->get_image_set("expandpatch_data");
114                                 expand->reposition_window(
115                                         patchbay->get_w() - 10 - expandpatch_data[0]->get_w(), 
116                                         y1 + y);
117 TRACE("PatchGUI::reposition 10\n");
118                                 x1 += expand->get_w();
119 TRACE("PatchGUI::reposition 11\n");
120                         }
121                 }
122                 y1 += mwindow->theme->play_h;
123         }
124         else
125         {
126                 y1 += mwindow->theme->title_h;
127                 y1 += mwindow->theme->play_h;
128         }
130         return y1;
133 int PatchGUI::update(int x, int y)
135 //TRACE("PatchGUI::update 1");
136         reposition(x, y);
137 //TRACE("PatchGUI::update 10");
139         int h = track->vertical_span(mwindow->theme);
140         int y1 = 0;
141         int x1 = 0;
142 //printf("PatchGUI::update 10\n");
144         if(title)
145         {
146                 if(h - y1 < 0)
147                 {
148                         delete title;
149                         title = 0;
150                 }
151                 else
152                 {
153                         title->update(track->title);
154                 }
155         }
156         else
157         if(h - y1 >= 0)
158         {
159                 patchbay->add_subwindow(title = new TitlePatch(mwindow, this, x1 + x, y1 + y));
160         }
161         y1 += mwindow->theme->title_h;
163         if(play)
164         {
165                 if(h - y1 < mwindow->theme->play_h)
166                 {
167                         delete play;
168                         delete record;
169                         delete gang;
170                         delete draw;
171                         delete mute;
172                         delete expand;
173                         play = 0;
174                         record = 0;
175                         draw = 0;
176                         mute = 0;
177                         expand = 0;
178                 }
179                 else
180                 {
181                         play->update(track->play);
182                         record->update(track->record);
183                         gang->update(track->gang);
184                         draw->update(track->draw);
185                         mute->update(mute->get_keyframe(mwindow, this)->value);
186                         expand->update(track->expand_view);
187                 }
188         }
189         else
190         if(h - y1 >= mwindow->theme->play_h)
191         {
192                 patchbay->add_subwindow(play = new PlayPatch(mwindow, this, x1 + x, y1 + y));
193 //printf("PatchGUI::update 1 %p %p\n", play, &play->status);
194                 x1 += play->get_w();
195                 patchbay->add_subwindow(record = new RecordPatch(mwindow, this, x1 + x, y1 + y));
196                 x1 += record->get_w();
197                 patchbay->add_subwindow(gang = new GangPatch(mwindow, this, x1 + x, y1 + y));
198                 x1 += gang->get_w();
199                 patchbay->add_subwindow(draw = new DrawPatch(mwindow, this, x1 + x, y1 + y));
200                 x1 += draw->get_w();
201                 patchbay->add_subwindow(mute = new MutePatch(mwindow, this, x1 + x, y1 + y));
202                 x1 += mute->get_w();
204                 VFrame **expandpatch_data = mwindow->theme->get_image_set("expandpatch_data");
205                 patchbay->add_subwindow(expand = new ExpandPatch(mwindow, 
206                         this, 
207                         patchbay->get_w() - 10 - expandpatch_data[0]->get_w(), 
208                         y1 + y));
209                 x1 += expand->get_w();
210         }
211         y1 += mwindow->theme->play_h;
213 //UNTRACE
214         return y1;
218 void PatchGUI::toggle_behavior(int type, 
219                 int value,
220                 BC_Toggle *toggle,
221                 int *output)
223         if(toggle->shift_down())
224         {
225                 int total_selected = mwindow->edl->tracks->total_of(type);
227 // nothing previously selected
228                 if(total_selected == 0)
229                 {
230                         mwindow->edl->tracks->select_all(type,
231                                 1);
232                 }
233                 else
234                 if(total_selected == 1)
235                 {
236 // this patch was previously the only one on
237                         if(*output)
238                         {
239                                 mwindow->edl->tracks->select_all(type,
240                                         1);
241                         }
242 // another patch was previously the only one on
243                         else
244                         {
245                                 mwindow->edl->tracks->select_all(type,
246                                         0);
247                                 *output = 1;
248                         }
249                 }
250                 else
251                 if(total_selected > 1)
252                 {
253                         mwindow->edl->tracks->select_all(type,
254                                 0);
255                         *output = 1;
256                 }
257                 toggle->set_value(*output);
258                 patchbay->update();
259                 patchbay->drag_operation = type;
260                 patchbay->new_status = 1;
261                 patchbay->button_down = 1;
262         }
263         else
264         {
265                 *output = value;
266 // Select + drag behavior
267                 patchbay->drag_operation = type;
268                 patchbay->new_status = value;
269                 patchbay->button_down = 1;
270         }
272         switch(type)
273         {
274                 case Tracks::PLAY:
275                         mwindow->gui->unlock_window();
276                         mwindow->restart_brender();
277                         mwindow->sync_parameters(CHANGE_EDL);
278                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 1");
279                         mwindow->undo->update_undo(_("play patch"), LOAD_PATCHES);
280                         break;
282                 case Tracks::MUTE:
283                         mwindow->gui->unlock_window();
284                         mwindow->restart_brender();
285                         mwindow->sync_parameters(CHANGE_PARAMS);
286                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 2");
287                         mwindow->undo->update_undo(_("mute patch"), LOAD_PATCHES);
288                         break;
290 // Update affected tracks in cwindow
291                 case Tracks::RECORD:
292                         mwindow->cwindow->update(0, 1, 1);
293                         mwindow->undo->update_undo(_("record patch"), LOAD_PATCHES);
294                         break;
296                 case Tracks::GANG:
297                         mwindow->undo->update_undo(_("gang patch"), LOAD_PATCHES);
298                         break;
300                 case Tracks::DRAW:
301                         mwindow->undo->update_undo(_("draw patch"), LOAD_PATCHES);
302                         mwindow->gui->update(0, 1, 0, 0, 0, 0, 0);
303                         break;
305                 case Tracks::EXPAND:
306                         mwindow->undo->update_undo(_("expand patch"), LOAD_PATCHES);
307                         break;
308         }
312 char* PatchGUI::calculate_nudge_text(int *changed)
314         if(changed) *changed = 0;
315         if(track->edl->session->nudge_seconds)
316         {
317                 sprintf(string_return, "%.4f", track->from_units(track->nudge));
318                 if(changed && nudge && atof(nudge->get_text()) - atof(string_return) != 0)
319                         *changed = 1;
320         }
321         else
322         {
323                 sprintf(string_return, "%d", track->nudge);
324                 if(changed && nudge && atoi(nudge->get_text()) - atoi(string_return) != 0)
325                         *changed = 1;
326         }
327         return string_return;
331 int64_t PatchGUI::calculate_nudge(char *string)
333         if(mwindow->edl->session->nudge_seconds)
334         {
335                 float result;
336                 sscanf(string, "%f", &result);
337                 return track->to_units(result, 0);
338         }
339         else
340         {
341                 int64_t temp;
342                 sscanf(string, "%lld", &temp);
343                 return temp;
344         }
358 PlayPatch::PlayPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
359  : BC_Toggle(x, 
360                 y, 
361                 mwindow->theme->get_image_set("playpatch_data"),
362                 patch->track->play, 
363                 "",
364                 0,
365                 0,
366                 0)
368         this->mwindow = mwindow;
369         this->patch = patch;
370         set_tooltip(_("Play track"));
371         set_select_drag(1);
374 int PlayPatch::button_press_event()
376         if(is_event_win() && get_buttonpress() == 1)
377         {
378                 set_status(BC_Toggle::TOGGLE_DOWN);
379                 update(!get_value());
380                 patch->toggle_behavior(Tracks::PLAY,
381                         get_value(),
382                         this,
383                         &patch->track->play);
384                 return 1;
385         }
386         return 0;
389 int PlayPatch::button_release_event()
391         int result = BC_Toggle::button_release_event();
392         if(patch->patchbay->drag_operation != Tracks::NONE)
393         {
394                 patch->patchbay->drag_operation = Tracks::NONE;
395         }
396         return result;
409 RecordPatch::RecordPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
410  : BC_Toggle(x, 
411                 y, 
412                 mwindow->theme->get_image_set("recordpatch_data"),
413                 patch->track->record, 
414                 "",
415                 0,
416                 0,
417                 0)
419         this->mwindow = mwindow;
420         this->patch = patch;
421         set_tooltip(_("Arm track"));
422         set_select_drag(1);
425 int RecordPatch::button_press_event()
427         if(is_event_win() && get_buttonpress() == 1)
428         {
429                 set_status(BC_Toggle::TOGGLE_DOWN);
430                 update(!get_value());
431                 patch->toggle_behavior(Tracks::RECORD,
432                         get_value(),
433                         this,
434                         &patch->track->record);
435                 return 1;
436         }
437         return 0;
440 int RecordPatch::button_release_event()
442         int result = BC_Toggle::button_release_event();
443         if(patch->patchbay->drag_operation != Tracks::NONE)
444         {
445                 patch->patchbay->drag_operation = Tracks::NONE;
446         }
447         return result;
460 GangPatch::GangPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
461  : BC_Toggle(x, y, 
462                 mwindow->theme->get_image_set("gangpatch_data"),
463                 patch->track->gang, 
464                 "",
465                 0,
466                 0,
467                 0)
469         this->mwindow = mwindow;
470         this->patch = patch;
471         set_tooltip(_("Gang faders"));
472         set_select_drag(1);
475 int GangPatch::button_press_event()
477         if(is_event_win() && get_buttonpress() == 1)
478         {
479                 set_status(BC_Toggle::TOGGLE_DOWN);
480                 update(!get_value());
481                 patch->toggle_behavior(Tracks::GANG,
482                         get_value(),
483                         this,
484                         &patch->track->gang);
485                 return 1;
486         }
487         return 0;
490 int GangPatch::button_release_event()
492         int result = BC_Toggle::button_release_event();
493         if(patch->patchbay->drag_operation != Tracks::NONE)
494         {
495                 patch->patchbay->drag_operation = Tracks::NONE;
496         }
497         return result;
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)
519         this->mwindow = mwindow;
520         this->patch = patch;
521         set_tooltip(_("Draw media"));
522         set_select_drag(1);
525 int DrawPatch::button_press_event()
527         if(is_event_win() && get_buttonpress() == 1)
528         {
529                 set_status(BC_Toggle::TOGGLE_DOWN);
530                 update(!get_value());
531                 patch->toggle_behavior(Tracks::DRAW,
532                         get_value(),
533                         this,
534                         &patch->track->draw);
535                 return 1;
536         }
537         return 0;
540 int DrawPatch::button_release_event()
542         int result = BC_Toggle::button_release_event();
543         if(patch->patchbay->drag_operation != Tracks::NONE)
544         {
545                 patch->patchbay->drag_operation = Tracks::NONE;
546         }
547         return result;
559 MutePatch::MutePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
560  : BC_Toggle(x, y, 
561                 mwindow->theme->get_image_set("mutepatch_data"),
562                 get_keyframe(mwindow, patch)->value, 
563                 "",
564                 0,
565                 0,
566                 0)
568         this->mwindow = mwindow;
569         this->patch = patch;
570         set_tooltip(_("Don't send to output"));
571         set_select_drag(1);
574 int MutePatch::button_press_event()
576         if(is_event_win() && get_buttonpress() == 1)
577         {
578                 set_status(BC_Toggle::TOGGLE_DOWN);
579                 update(!get_value());
580                 IntAuto *current;
581                 double position = mwindow->edl->local_session->get_selectionstart(1);
582                 Autos *mute_autos = patch->track->automation->autos[AUTOMATION_MUTE];
585                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
586                 current->value = get_value();
588                 patch->toggle_behavior(Tracks::MUTE,
589                         get_value(),
590                         this,
591                         &current->value);
594                 mwindow->undo->update_undo(_("keyframe"), LOAD_AUTOMATION);
596                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
597                 {
598                         mwindow->gui->canvas->draw_overlays();
599                         mwindow->gui->canvas->flash();
600                 }
601                 return 1;
602         }
603         return 0;
606 int MutePatch::button_release_event()
608         int result = BC_Toggle::button_release_event();
609         if(patch->patchbay->drag_operation != Tracks::NONE)
610         {
611                 patch->patchbay->drag_operation = Tracks::NONE;
612         }
613         return result;
616 IntAuto* MutePatch::get_keyframe(MWindow *mwindow, PatchGUI *patch)
618         Auto *current = 0;
619         double unit_position = mwindow->edl->local_session->get_selectionstart(1);
620         unit_position = mwindow->edl->align_to_frame(unit_position, 0);
621         unit_position = patch->track->to_units(unit_position, 0);
622         return (IntAuto*)patch->track->automation->autos[AUTOMATION_MUTE]->get_prev_auto(
623                 (int64_t)unit_position, 
624                 PLAY_FORWARD,
625                 current);
639 ExpandPatch::ExpandPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
640  : BC_Toggle(x, 
641                 y, 
642                 mwindow->theme->get_image_set("expandpatch_data"),
643                 patch->track->expand_view, 
644                 "",
645                 0,
646                 0,
647                 0)
649         this->mwindow = mwindow;
650         this->patch = patch;
651         set_select_drag(1);
654 int ExpandPatch::button_press_event()
656         if(is_event_win() && get_buttonpress() == 1)
657         {
658                 set_status(BC_Toggle::TOGGLE_DOWN);
659                 update(!get_value());
660                 patch->toggle_behavior(Tracks::EXPAND,
661                         get_value(),
662                         this,
663                         &patch->track->expand_view);
664                 mwindow->trackmovement(mwindow->edl->local_session->track_start);
665                 return 1;
666         }
667         return 0;
670 int ExpandPatch::button_release_event()
672         int result = BC_Toggle::button_release_event();
673         if(patch->patchbay->drag_operation != Tracks::NONE)
674         {
675                 patch->patchbay->drag_operation = Tracks::NONE;
676         }
677         return result;
684 TitlePatch::TitlePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
685  : BC_TextBox(x, 
686                 y, 
687                 patch->patchbay->get_w() - 10, 
688                 1,
689                 patch->track->title)
691         this->mwindow = mwindow;
692         this->patch = patch;
695 int TitlePatch::handle_event()
697         strcpy(patch->track->title, get_text());
698         mwindow->update_plugin_titles();
699         mwindow->gui->canvas->draw_overlays();
700         mwindow->gui->canvas->flash();
701         mwindow->undo->update_undo(_("track title"), LOAD_PATCHES);
702         return 1;
713 NudgePatch::NudgePatch(MWindow *mwindow, 
714         PatchGUI *patch, 
715         int x, 
716         int y, 
717         int w)
718  : BC_TextBox(x,
719         y,
720         w,
721         1,
722         patch->calculate_nudge_text(0))
724         this->mwindow = mwindow;
725         this->patch = patch;
726         set_tooltip(_("Nudge"));
729 int NudgePatch::handle_event()
731         set_value(patch->calculate_nudge(get_text()));
732         return 1;
735 void NudgePatch::set_value(int64_t value)
737         patch->track->nudge = value;
739         if(patch->track->gang)
740                 patch->patchbay->synchronize_nudge(patch->track->nudge, patch->track);
742         mwindow->undo->update_undo("nudge", LOAD_AUTOMATION, this);
744         mwindow->gui->unlock_window();
745         if(patch->track->data_type == TRACK_VIDEO)
746                 mwindow->restart_brender();
747         mwindow->sync_parameters(CHANGE_PARAMS);
748         mwindow->gui->lock_window("NudgePatch::handle_event 2");
750         mwindow->session->changes_made = 1;
754 int NudgePatch::button_press_event()
756         int result = 0;
758         if(is_event_win() && cursor_inside())
759         {
760                 if(get_buttonpress() == 4)
761                 {
762                         int value = patch->calculate_nudge(get_text());
763                         value += calculate_increment();
764                         set_value(value);
765                         update();
766                         result = 1;
767                 }
768                 else
769                 if(get_buttonpress() == 5)
770                 {
771                         int value = patch->calculate_nudge(get_text());
772                         value -= calculate_increment();
773                         set_value(value);
774                         update();
775                         result = 1;
776                 }
777                 else
778                 if(get_buttonpress() == 3)
779                 {
780                         patch->patchbay->nudge_popup->activate_menu(patch);
781                         result = 1;
782                 }
783         }
785         if(!result)
786                 return BC_TextBox::button_press_event();
787         else
788                 return result;
791 int64_t NudgePatch::calculate_increment()
793         if(patch->track->data_type == TRACK_AUDIO)
794         {
795                 return (int64_t)ceil(patch->track->edl->session->sample_rate / 10);
796         }
797         else
798         {
799                 return (int64_t)ceil(1.0 / patch->track->edl->session->frame_rate);
800         }
803 void NudgePatch::update()
805         int changed;
806         char *string = patch->calculate_nudge_text(&changed);
807         if(changed)
808                 BC_TextBox::update(string);