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