improve resize flash operation, fixup xv grab/ungrab, fixup label updates
[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                 // all selected if nothing previously selected or
243                 // if this patch was previously the only one selected
244                 switch( type ) {
245                 case Tracks::MUTE: {  // negative logic for normally off
246                         int total_selected = mwindow->edl->tracks->total() -
247                                 mwindow->edl->tracks->total_of(type);
248                         int current_output = *output;
249                         int selected = !total_selected || (total_selected == 1 &&
250                                  !current_output ) ? 0 : 1;
251                         mwindow->edl->tracks->select_all(type, selected);
252                         if( selected ) *output = 0;
253                         break; }
254                 default: {
255                         int total_selected = mwindow->edl->tracks->total_of(type);
256                         int current_output = *output;
257                         int selected = !total_selected || (total_selected == 1 &&
258                                  current_output ) ? 1 : 0;
259                         mwindow->edl->tracks->select_all(type, selected);
260                         if( !selected ) *output = 1;
261                         break; }
262                 }
263
264                 patchbay->drag_operation = type;
265                 patchbay->new_status = 1;
266         }
267         else
268         {
269                 *output = value;
270 // Select + drag behavior
271                 patchbay->drag_operation = type;
272                 patchbay->new_status = value;
273         }
274
275         switch(type)
276         {
277                 case Tracks::PLAY:
278                         mwindow->gui->unlock_window();
279                         mwindow->restart_brender();
280                         mwindow->sync_parameters(CHANGE_EDL);
281                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 1");
282                         break;
283
284                 case Tracks::MUTE:
285                         mwindow->gui->unlock_window();
286                         mwindow->restart_brender();
287                         mwindow->sync_parameters(CHANGE_PARAMS);
288                         mwindow->gui->lock_window("PatchGUI::toggle_behavior 2");
289                         break;
290
291 // Update affected tracks in cwindow
292                 case Tracks::RECORD:
293                         mwindow->cwindow->update(0, 1, 1);
294                         break;
295
296                 case Tracks::GANG:
297                         break;
298
299                 case Tracks::DRAW:
300                         mwindow->gui->update(0, 1, 0, 0, 0, 0, 0);
301                         break;
302
303                 case Tracks::EXPAND:
304                         break;
305         }
306
307 // update all panes
308         mwindow->gui->update_patchbay();
309 }
310
311
312 char* PatchGUI::calculate_nudge_text(int *changed)
313 {
314         if(changed) *changed = 0;
315         if(track->edl->session->nudge_format)
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, "%jd", track->nudge);
324                 if(changed && nudge && atoi(nudge->get_text()) - atoi(string_return) != 0)
325                         *changed = 1;
326         }
327         return string_return;
328 }
329
330
331 int64_t PatchGUI::calculate_nudge(const char *string)
332 {
333         if(mwindow->edl->session->nudge_format)
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, "%jd", &temp);
343                 return temp;
344         }
345 }
346
347
348
349
350
351
352
353
354
355
356
357
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)
367 {
368         this->mwindow = mwindow;
369         this->patch = patch;
370         set_tooltip(_("Play track"));
371         set_select_drag(1);
372 }
373
374 int PlayPatch::button_press_event()
375 {
376         if(is_event_win() && get_buttonpress() == 1)
377         {
378                 mwindow->undo->update_undo_before();
379                 set_status(BC_Toggle::TOGGLE_DOWN);
380                 update(!get_value());
381                 patch->toggle_behavior(Tracks::PLAY,
382                         get_value(),
383                         this,
384                         &patch->track->play);
385                 return 1;
386         }
387         return 0;
388 }
389
390 int PlayPatch::button_release_event()
391 {
392         int result = BC_Toggle::button_release_event();
393         if(patch->patchbay->drag_operation == Tracks::PLAY)
394         {
395                 mwindow->undo->update_undo_after(_("play patch"), LOAD_PATCHES);
396                 patch->patchbay->drag_operation = Tracks::NONE;
397         }
398         return result;
399 }
400
401
402
403
404
405
406
407
408
409
410
411 RecordPatch::RecordPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
412  : BC_Toggle(x,
413                 y,
414                 mwindow->theme->get_image_set("recordpatch_data"),
415                 patch->track->record,
416                 "",
417                 0,
418                 0,
419                 0)
420 {
421         this->mwindow = mwindow;
422         this->patch = patch;
423         set_tooltip(_("Arm track"));
424         set_select_drag(1);
425 }
426
427 int RecordPatch::button_press_event()
428 {
429         if(is_event_win() && get_buttonpress() == 1)
430         {
431                 mwindow->undo->update_undo_before();
432                 set_status(BC_Toggle::TOGGLE_DOWN);
433                 update(!get_value());
434                 patch->toggle_behavior(Tracks::RECORD,
435                         get_value(),
436                         this,
437                         &patch->track->record);
438                 return 1;
439         }
440         return 0;
441 }
442
443 int RecordPatch::button_release_event()
444 {
445         int result = BC_Toggle::button_release_event();
446         if(patch->patchbay->drag_operation == Tracks::RECORD)
447         {
448                 mwindow->undo->update_undo_after(_("record patch"), LOAD_PATCHES);
449                 patch->patchbay->drag_operation = Tracks::NONE;
450         }
451         return result;
452 }
453
454
455
456
457
458
459
460
461
462
463
464 GangPatch::GangPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
465  : BC_Toggle(x, y,
466                 mwindow->theme->get_image_set("gangpatch_data"),
467                 patch->track->gang,
468                 "",
469                 0,
470                 0,
471                 0)
472 {
473         this->mwindow = mwindow;
474         this->patch = patch;
475         set_tooltip(_("Gang faders"));
476         set_select_drag(1);
477 }
478
479 int GangPatch::button_press_event()
480 {
481         if(is_event_win() && get_buttonpress() == 1)
482         {
483                 mwindow->undo->update_undo_before();
484                 set_status(BC_Toggle::TOGGLE_DOWN);
485                 update(!get_value());
486                 patch->toggle_behavior(Tracks::GANG,
487                         get_value(),
488                         this,
489                         &patch->track->gang);
490                 return 1;
491         }
492         return 0;
493 }
494
495 int GangPatch::button_release_event()
496 {
497         int result = BC_Toggle::button_release_event();
498         if(patch->patchbay->drag_operation == Tracks::GANG)
499         {
500                 mwindow->undo->update_undo_after(_("gang patch"), LOAD_PATCHES);
501                 patch->patchbay->drag_operation = Tracks::NONE;
502         }
503         return result;
504 }
505
506
507
508
509
510
511
512
513
514
515
516 DrawPatch::DrawPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
517  : BC_Toggle(x, y,
518                 mwindow->theme->get_image_set("drawpatch_data"),
519                 patch->track->draw,
520                 "",
521                 0,
522                 0,
523                 0)
524 {
525         this->mwindow = mwindow;
526         this->patch = patch;
527         set_tooltip(_("Draw media"));
528         set_select_drag(1);
529 }
530
531 int DrawPatch::button_press_event()
532 {
533         if(is_event_win() && get_buttonpress() == 1)
534         {
535                 mwindow->undo->update_undo_before();
536                 set_status(BC_Toggle::TOGGLE_DOWN);
537                 update(!get_value());
538                 patch->toggle_behavior(Tracks::DRAW,
539                         get_value(),
540                         this,
541                         &patch->track->draw);
542                 return 1;
543         }
544         return 0;
545 }
546
547 int DrawPatch::button_release_event()
548 {
549         int result = BC_Toggle::button_release_event();
550         if(patch->patchbay->drag_operation == Tracks::DRAW)
551         {
552                 mwindow->undo->update_undo_after(_("draw patch"), LOAD_PATCHES);
553                 patch->patchbay->drag_operation = Tracks::NONE;
554         }
555         return result;
556 }
557
558
559
560
561
562
563
564
565
566
567 MutePatch::MutePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
568  : BC_Toggle(x, y,
569                 mwindow->theme->get_image_set("mutepatch_data"),
570                 get_keyframe(mwindow, patch)->value,
571                 "",
572                 0,
573                 0,
574                 0)
575 {
576         this->mwindow = mwindow;
577         this->patch = patch;
578         set_tooltip(_("Don't send to output"));
579         set_select_drag(1);
580 }
581
582 int MutePatch::button_press_event()
583 {
584         if(is_event_win() && get_buttonpress() == 1)
585         {
586                 mwindow->undo->update_undo_before();
587                 set_status(BC_Toggle::TOGGLE_DOWN);
588                 update(!get_value());
589                 IntAuto *current;
590                 double position = mwindow->edl->local_session->get_selectionstart(1);
591                 Autos *mute_autos = patch->track->automation->autos[AUTOMATION_MUTE];
592
593
594                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
595                 current->value = get_value();
596
597                 patch->toggle_behavior(Tracks::MUTE,
598                         get_value(),
599                         this,
600                         &current->value);
601
602
603
604                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
605                 {
606                         mwindow->gui->draw_overlays(1);
607                 }
608                 return 1;
609         }
610         return 0;
611 }
612
613 int MutePatch::button_release_event()
614 {
615         int result = BC_Toggle::button_release_event();
616         if(patch->patchbay->drag_operation == Tracks::MUTE)
617         {
618                 mwindow->undo->update_undo_after(_("mute patch"), LOAD_PATCHES);
619                 patch->patchbay->drag_operation = Tracks::NONE;
620         }
621         return result;
622 }
623
624 IntAuto* MutePatch::get_keyframe(MWindow *mwindow, PatchGUI *patch)
625 {
626         Auto *current = 0;
627         double unit_position = mwindow->edl->local_session->get_selectionstart(1);
628         unit_position = mwindow->edl->align_to_frame(unit_position, 0);
629         unit_position = patch->track->to_units(unit_position, 0);
630         return (IntAuto*)patch->track->automation->autos[AUTOMATION_MUTE]->get_prev_auto(
631                 (int64_t)unit_position,
632                 PLAY_FORWARD,
633                 current);
634 }
635
636
637
638
639
640
641
642
643
644
645
646
647 ExpandPatch::ExpandPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
648  : BC_Toggle(x,
649                 y,
650                 mwindow->theme->get_image_set("expandpatch_data"),
651                 patch->track->expand_view,
652                 "",
653                 0,
654                 0,
655                 0)
656 {
657         this->mwindow = mwindow;
658         this->patch = patch;
659         set_select_drag(1);
660 }
661
662 int ExpandPatch::button_press_event()
663 {
664         if(is_event_win() && get_buttonpress() == 1)
665         {
666                 mwindow->undo->update_undo_before();
667                 set_status(BC_Toggle::TOGGLE_DOWN);
668                 update(!get_value());
669                 patch->toggle_behavior(Tracks::EXPAND,
670                         get_value(),
671                         this,
672                         &patch->track->expand_view);
673                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
674                 mwindow->gui->draw_trackmovement();
675                 return 1;
676         }
677         return 0;
678 }
679
680 int ExpandPatch::button_release_event()
681 {
682         int result = BC_Toggle::button_release_event();
683         if(patch->patchbay->drag_operation == Tracks::EXPAND)
684         {
685                 mwindow->undo->update_undo_after(_("expand patch"), LOAD_PATCHES);
686                 patch->patchbay->drag_operation = Tracks::NONE;
687         }
688         return result;
689 }
690
691
692
693
694
695 TitlePatch::TitlePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
696  : BC_TextBox(x,
697                 y,
698                 patch->patchbay->get_w() - 10,
699                 1,
700                 patch->track->title,
701                 1, MEDIUMFONT, 1)
702 {
703         this->mwindow = mwindow;
704         this->patch = patch;
705 }
706
707 int TitlePatch::handle_event()
708 {
709         mwindow->undo->update_undo_before(_("track title"), this);
710         strcpy(patch->track->title, get_text());
711         mwindow->update_plugin_titles();
712         mwindow->gui->draw_overlays(1);
713         mwindow->undo->update_undo_after(_("track title"), LOAD_PATCHES);
714         return 1;
715 }
716
717
718
719
720
721
722
723
724
725 NudgePatch::NudgePatch(MWindow *mwindow,
726         PatchGUI *patch,
727         int x,
728         int y,
729         int w)
730  : BC_TextBox(x,
731         y,
732         w,
733         1,
734         patch->calculate_nudge_text(0))
735 {
736         this->mwindow = mwindow;
737         this->patch = patch;
738         set_tooltip(_("Nudge"));
739 }
740
741 int NudgePatch::handle_event()
742 {
743         set_value(patch->calculate_nudge(get_text()));
744         return 1;
745 }
746
747 void NudgePatch::set_value(int64_t value)
748 {
749         mwindow->undo->update_undo_before(_("nudge"), this);
750         patch->track->nudge = value;
751
752         if(patch->track->gang && patch->track->record)
753                 patch->patchbay->synchronize_nudge(patch->track->nudge, patch->track);
754
755         mwindow->undo->update_undo_after(_("nudge"), LOAD_PATCHES);
756
757         mwindow->gui->unlock_window();
758         if(patch->track->data_type == TRACK_VIDEO)
759                 mwindow->restart_brender();
760         mwindow->sync_parameters(CHANGE_PARAMS);
761         mwindow->gui->lock_window("NudgePatch::handle_event 2");
762
763         mwindow->session->changes_made = 1;
764 }
765
766
767 int NudgePatch::button_press_event()
768 {
769         int result = 0;
770
771         if(is_event_win() && cursor_inside())
772         {
773                 if(get_buttonpress() == 4)
774                 {
775                         int value = patch->calculate_nudge(get_text());
776                         value += calculate_increment();
777                         set_value(value);
778                         update();
779                         result = 1;
780                 }
781                 else
782                 if(get_buttonpress() == 5)
783                 {
784                         int value = patch->calculate_nudge(get_text());
785                         value -= calculate_increment();
786                         set_value(value);
787                         update();
788                         result = 1;
789                 }
790                 else
791                 if(get_buttonpress() == 3)
792                 {
793                         patch->patchbay->nudge_popup->activate_menu(patch);
794                         result = 1;
795                 }
796         }
797
798         if(!result)
799                 return BC_TextBox::button_press_event();
800         else
801                 return result;
802 }
803
804 int64_t NudgePatch::calculate_increment()
805 {
806         if(patch->track->data_type == TRACK_AUDIO)
807         {
808                 return (int64_t)ceil(patch->track->edl->session->sample_rate / 10.0);
809         }
810         else
811         {
812                 return (int64_t)ceil(1.0 / patch->track->edl->session->frame_rate);
813         }
814 }
815
816 void NudgePatch::update()
817 {
818         int changed;
819         char *string = patch->calculate_nudge_text(&changed);
820         if(changed)
821                 BC_TextBox::update(string);
822 }
823
824
825
826