initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / patchbay.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 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 "apatchgui.h"
23 #include "automation.h"
24 #include "floatauto.h"
25 #include "floatautos.h"
26 #include "clip.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "filexml.h"
30 #include "intauto.h"
31 #include "intautos.h"
32 #include "language.h"
33 #include "localsession.h"
34 #include "mainundo.h"
35 #include "mwindow.h"
36 #include "mwindowgui.h"
37 #include "patchbay.h"
38 #include "patchgui.h"
39 #include "mainsession.h"
40 #include "strack.h"
41 #include "theme.h"
42 #include "timelinepane.h"
43 #include "track.h"
44 #include "trackcanvas.h"
45 #include "tracks.h"
46 #include "vpatchgui.h"
47
48
49
50
51
52
53 NudgePopup::NudgePopup(MWindow *mwindow, PatchBay *patchbay)
54  : BC_PopupMenu(0, 
55                 0, 
56                 0, 
57                 "", 
58                 0)
59 {
60         this->mwindow = mwindow;
61         this->patchbay = patchbay;
62 }
63
64 NudgePopup::~NudgePopup()
65 {
66 }
67
68
69 void NudgePopup::create_objects()
70 {
71         add_item(seconds_item = new NudgePopupSeconds(this));
72         add_item(native_item = new NudgePopupNative(this));
73 }
74
75 void NudgePopup::activate_menu(PatchGUI *gui)
76 {
77 // Set checked status
78         seconds_item->set_checked(mwindow->edl->session->nudge_seconds ? 1 : 0);
79         native_item->set_checked(mwindow->edl->session->nudge_seconds ? 0 : 1);
80
81 // Set native units to track format
82         native_item->set_text(gui->track->data_type == TRACK_AUDIO ? 
83                 (char*)"Samples" : 
84                 (char*)"Frames");
85
86 // Show it
87         BC_PopupMenu::activate_menu();
88 }
89
90
91
92 NudgePopupSeconds::NudgePopupSeconds(NudgePopup *popup)
93  : BC_MenuItem("Seconds")
94 {
95         this->popup = popup;
96 }
97
98 int NudgePopupSeconds::handle_event()
99 {
100         popup->mwindow->edl->session->nudge_seconds = 1;
101         popup->mwindow->gui->update_patchbay();
102         return 1;
103 }
104
105
106
107
108
109 NudgePopupNative::NudgePopupNative(NudgePopup *popup)
110  : BC_MenuItem("")
111 {
112         this->popup = popup;
113 }
114
115 int NudgePopupNative::handle_event()
116 {
117         popup->mwindow->edl->session->nudge_seconds = 0;
118         popup->mwindow->gui->update_patchbay();
119         return 1;
120 }
121
122
123
124
125
126
127
128
129
130 PatchBay::PatchBay(MWindow *mwindow, MWindowGUI *gui)
131  : BC_SubWindow(mwindow->theme->patchbay_x,
132         mwindow->theme->patchbay_y,
133         mwindow->theme->patchbay_w,
134         mwindow->theme->patchbay_h)
135 {
136         this->mwindow = mwindow;
137         this->gui = gui;
138         this->pane = 0;
139         drag_operation = Tracks::NONE;
140         for(int i = 0; i < TRANSFER_TYPES; i++) mode_icons[i] = 0;
141 }
142
143 PatchBay::PatchBay(MWindow *mwindow, 
144         TimelinePane *pane, 
145         int x, 
146         int y, 
147         int w, 
148         int h)
149  : BC_SubWindow(x,
150         y,
151         w,
152         h)
153 {
154         this->mwindow = mwindow;
155         this->gui = mwindow->gui;
156         this->pane = pane;
157         drag_operation = Tracks::NONE;
158         for(int i = 0; i < TRANSFER_TYPES; i++) mode_icons[i] = 0;
159 // printf("PatchBay::PatchBay %d %d %d %d %d\n", 
160 // __LINE__,
161 // x,
162 // y,
163 // w,
164 // h);
165 }
166
167 PatchBay::~PatchBay() 
168 {
169         delete_all_patches();
170         for(int i = 0; i < TRANSFER_TYPES; i++) delete mode_icons[i];
171 }
172
173
174 int PatchBay::delete_all_patches()
175 {
176     patches.remove_all_objects();
177     return 0;
178 }
179
180 void PatchBay::create_objects()
181 {
182         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
183         flash(0);
184
185 // Create icons for mode types
186         static const char *mode_types[] = {
187                 "mode_normal",
188                 "mode_add",
189                 "mode_subtract",
190                 "mode_multiply",
191                 "mode_divide",
192                 "mode_replace",
193                 "mode_max",
194                 "mode_min",
195                 "mode_average",
196                 "mode_darken",
197                 "mode_lighten",
198                 "mode_dst",
199                 "mode_dstatop",
200                 "mode_dstin",
201                 "mode_dstout",
202                 "mode_dstover",
203                 "mode_src",
204                 "mode_srcatop",
205                 "mode_srcin",
206                 "mode_srcout",
207                 "mode_srcover",
208                 "mode_or",
209                 "mode_xor",
210         };
211         for( int mode=0; mode<TRANSFER_TYPES; ++mode ) {
212                 mode_icons[mode] = new BC_Pixmap(this,
213                         mwindow->theme->get_image(mode_types[mode]),
214                         PIXMAP_ALPHA);
215         }
216
217         add_subwindow(nudge_popup = new NudgePopup(mwindow, this));
218         nudge_popup->create_objects();
219         update();
220 }
221
222 BC_Pixmap* PatchBay::mode_to_icon(int mode)
223 {
224         return mode_icons[mode];
225 }
226
227 int PatchBay::icon_to_mode(BC_Pixmap *icon)
228 {
229         for(int i = 0; i < TRANSFER_TYPES; i++)
230                 if(icon == mode_icons[i]) return i;
231         return TRANSFER_NORMAL;
232 }
233
234 void PatchBay::resize_event()
235 {
236         reposition_window(mwindow->theme->patchbay_x,
237                 mwindow->theme->patchbay_y,
238                 mwindow->theme->patchbay_w,
239                 mwindow->theme->patchbay_h);
240         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
241         update();
242         flash(0);
243 }
244
245 void PatchBay::resize_event(int x, int y, int w, int h)
246 {
247         reposition_window(x,
248                 y,
249                 w,
250                 h);
251         draw_top_background(get_parent(), 0, 0, w, h);
252         update();
253         flash(0);
254 }
255
256 int PatchBay::button_press_event()
257 {
258         int result = 0;
259 // Too much junk to support the wheel
260         return result;
261 }
262
263 int PatchBay::cursor_motion_event()
264 {
265         //int cursor_x = get_relative_cursor_x();
266         int cursor_y = get_relative_cursor_y();
267         int update_gui = 0;
268
269         if(drag_operation != Tracks::NONE)
270         {
271                 if(cursor_y >= 0 &&
272                         cursor_y < get_h())
273                 {
274 // Get track we're inside of
275                         for(Track *track = mwindow->edl->tracks->first;
276                                 track;
277                                 track = track->next)
278                         {
279                                 int y = track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
280                                 int h = track->vertical_span(mwindow->theme);
281                                 if(cursor_y >= y && cursor_y < y + h)
282                                 {
283                                         switch(drag_operation)
284                                         {
285                                                 case Tracks::PLAY:
286                                                         if(track->play != new_status)
287                                                         {
288                                                                 track->play = new_status;
289                                                                 mwindow->gui->unlock_window();
290                                                                 mwindow->restart_brender();
291                                                                 mwindow->sync_parameters(CHANGE_EDL);
292                                                                 mwindow->gui->lock_window();
293                                                                 update_gui = 1;
294                                                         }
295                                                         break;
296                                                 case Tracks::RECORD:
297                                                         if(track->record != new_status)
298                                                         {
299                                                                 track->record = new_status;
300                                                                 update_gui = 1;
301                                                         }
302                                                         break;
303                                                 case Tracks::GANG:
304                                                         if(track->gang != new_status)
305                                                         {
306                                                                 track->gang = new_status;
307                                                                 update_gui = 1;
308                                                         }
309                                                         break;
310                                                 case Tracks::DRAW:
311                                                         if(track->draw != new_status)
312                                                         {
313                                                                 track->draw = new_status;
314                                                                 update_gui = 1;
315                                                         }
316                                                         break;
317                                                 case Tracks::EXPAND:
318                                                         if(track->expand_view != new_status)
319                                                         {
320                                                                 track->expand_view = new_status;
321                                                                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
322                                                                 gui->draw_trackmovement();
323                                                                 update_gui = 0;
324                                                         }
325                                                         break;
326                                                 case Tracks::MUTE:
327                                                 {
328                                                         IntAuto *current = 0;
329                                                         Auto *keyframe = 0;
330                                                         double position = mwindow->edl->local_session->get_selectionstart(1);
331                                                         Autos *mute_autos = track->automation->autos[AUTOMATION_MUTE];
332
333                                                         current = (IntAuto*)mute_autos->get_prev_auto(PLAY_FORWARD, 
334                                                                 keyframe);
335
336                                                         if(current->value != new_status)
337                                                         {
338
339 //                                                              mwindow->undo->update_undo_before(_("keyframe"), this);
340                                                                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
341
342                                                                 current->value = new_status;
343
344 //                                                              mwindow->undo->update_undo_after(_("keyframe"), LOAD_AUTOMATION);
345
346                                                                 mwindow->gui->unlock_window();
347                                                                 mwindow->restart_brender();
348                                                                 mwindow->sync_parameters(CHANGE_PARAMS);
349                                                                 mwindow->gui->lock_window();
350
351                                                                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
352                                                                 {
353                                                                         gui->draw_overlays(1);
354                                                                 }
355                                                                 update_gui = 1;
356                                                         }
357                                                         break;
358                                                 }
359                                         }
360                                 }
361                         }
362                 }
363         }
364
365         if(update_gui)
366         {
367                 gui->update_patchbay();
368         }
369         return 0;
370 }
371
372 void PatchBay::set_meter_format(int mode, int min, int max)
373 {
374         for(int i = 0; i < patches.total; i++)
375         {
376                 PatchGUI *patchgui = patches.values[i];
377                 if(patchgui->data_type == TRACK_AUDIO)
378                 {
379                         APatchGUI *apatchgui = (APatchGUI*)patchgui;
380                         if(apatchgui->meter)
381                         {
382                                 apatchgui->meter->change_format(mode, min, max);
383                         }
384                 }
385         }
386 }
387
388 void PatchBay::update_meters(ArrayList<double> *module_levels)
389 {
390         for(int level_number = 0, patch_number = 0;
391                 patch_number < patches.total && level_number < module_levels->total;
392                 patch_number++)
393         {
394                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
395
396                 if(patchgui->data_type == TRACK_AUDIO)
397                 {
398                         if(patchgui->meter)
399                         {
400                                 double level = module_levels->values[level_number];
401                                 patchgui->meter->update(level, level > 1);
402                         }
403
404                         level_number++;
405                 }
406         }
407 }
408
409 void PatchBay::reset_meters()
410 {
411         for(int patch_number = 0;
412                 patch_number < patches.total;
413                 patch_number++)
414         {
415                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
416                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
417                 {
418                         patchgui->meter->reset_over();
419                 }
420         }
421 }
422
423 void PatchBay::stop_meters()
424 {
425         for(int patch_number = 0;
426                 patch_number < patches.total;
427                 patch_number++)
428         {
429                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
430                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
431                 {
432                         patchgui->meter->reset();
433                 }
434         }
435 }
436
437
438 #define PATCH_X 3
439
440 int PatchBay::update()
441 {
442         int patch_count = 0;
443
444 // Every patch has a GUI regardless of whether or not it is visible.
445 // Make sure GUI's are allocated for every patch and deleted for non-existant
446 // patches.
447         for(Track *current = mwindow->edl->tracks->first;
448                 current;
449                 current = NEXT, patch_count++)
450         {
451                 PatchGUI *patchgui = 0;
452                 int y = current->y_pixel;
453                 y -= mwindow->edl->local_session->track_start[pane->number];
454
455 //printf("PatchBay::update %d %d\n", __LINE__, y);
456                 if(patches.total > patch_count)
457                 {
458                         if(patches.values[patch_count]->track_id != current->get_id())
459                         {
460                                 delete patches.values[patch_count];
461
462                                 switch(current->data_type)
463                                 {
464                                         case TRACK_AUDIO:
465                                                 patchgui = patches.values[patch_count] = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
466                                                 break;
467                                         case TRACK_VIDEO:
468                                                 patchgui = patches.values[patch_count] = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
469                                                 break;
470                                         case TRACK_SUBTITLE:
471                                                 patchgui = patches.values[patch_count] = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
472                                                 break;
473                                 }
474                                 patchgui->create_objects();
475                         }
476                         else
477                         {
478                                 patches.values[patch_count]->update(PATCH_X, y);
479                         }
480                 }
481                 else
482                 {
483                         switch(current->data_type)
484                         {
485                                 case TRACK_AUDIO:
486                                         patchgui = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
487                                         break;
488                                 case TRACK_VIDEO:
489                                         patchgui = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
490                                         break;
491                                 case TRACK_SUBTITLE:
492                                         patchgui = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
493                                         break;
494                         }
495                         patches.append(patchgui);
496                         patchgui->create_objects();
497                 }
498         }
499
500         while(patches.total > patch_count)
501         {
502                 delete patches.values[patches.total - 1];
503                 patches.remove_number(patches.total - 1);
504         }
505
506         show_window(0);
507         return 0;
508 }
509
510 void PatchBay::synchronize_faders(float change, int data_type, Track *skip)
511 {
512         for(Track *current = mwindow->edl->tracks->first;
513                 current;
514                 current = NEXT)
515         {
516                 if(current->data_type == data_type &&
517                         current->gang && 
518                         current->record && 
519                         current != skip)
520                 {
521                         FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
522                         double position = mwindow->edl->local_session->get_selectionstart(1);
523
524
525                         FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_for_editing(position);
526
527                         keyframe->value += change;
528                         if(data_type == TRACK_AUDIO)
529                                 CLAMP(keyframe->value, INFINITYGAIN, MAX_AUDIO_FADE);
530                         else
531                                 CLAMP(keyframe->value, 0, MAX_VIDEO_FADE);
532
533
534                         PatchGUI *patch = get_patch_of(current);
535                         if(patch) patch->update(patch->x, patch->y);
536                 }
537         }
538 }
539
540 void PatchBay::synchronize_nudge(int64_t value, Track *skip)
541 {
542         for(Track *current = mwindow->edl->tracks->first;
543                 current;
544                 current = NEXT)
545         {
546                 if(current->data_type == skip->data_type &&
547                         current->gang &&
548                         current->record &&
549                         current != skip)
550                 {
551                         current->nudge = value;
552                         PatchGUI *patch = get_patch_of(current);
553                         if(patch) patch->update(patch->x, patch->y);
554                 }
555         }
556 }
557
558 PatchGUI* PatchBay::get_patch_of(Track *track)
559 {
560         for(int i = 0; i < patches.total; i++)
561         {
562                 if(patches.values[i]->track == track)
563                         return patches.values[i];
564         }
565         return 0;
566 }
567
568 int PatchBay::resize_event(int top, int bottom)
569 {
570         reposition_window(mwindow->theme->patchbay_x,
571                 mwindow->theme->patchbay_y,
572                 mwindow->theme->patchbay_w,
573                 mwindow->theme->patchbay_h);
574         return 0;
575 }
576
577