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