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