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