improve delays created by vicon drawing locks, reset_cache segv fix, gang track toolt...
[goodguy/cinelerra.git] / cinelerra-5.1 / 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_format ? 1 : 0);
79         native_item->set_checked(mwindow->edl->session->nudge_format ? 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_format = 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_format = 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_darken",
196                 "mode_lighten",
197                 "mode_dst",
198                 "mode_dstatop",
199                 "mode_dstin",
200                 "mode_dstout",
201                 "mode_dstover",
202                 "mode_src",
203                 "mode_srcatop",
204                 "mode_srcin",
205                 "mode_srcout",
206                 "mode_srcover",
207                 "mode_and",
208                 "mode_or",
209                 "mode_xor",
210                 "mode_overlay",
211                 "mode_screen",
212                 "mode_burn",
213                 "mode_dodge",
214                 "mode_hardlight",
215                 "mode_softlight",
216                 "mode_difference",
217         };
218         for( int mode=0; mode<TRANSFER_TYPES; ++mode ) {
219                 mode_icons[mode] = new BC_Pixmap(this,
220                         mwindow->theme->get_image(mode_types[mode]),
221                         PIXMAP_ALPHA);
222         }
223
224         add_subwindow(nudge_popup = new NudgePopup(mwindow, this));
225         nudge_popup->create_objects();
226         update();
227 }
228
229 BC_Pixmap* PatchBay::mode_to_icon(int mode)
230 {
231         return mode_icons[mode];
232 }
233
234 int PatchBay::icon_to_mode(BC_Pixmap *icon)
235 {
236         for(int i = 0; i < TRANSFER_TYPES; i++)
237                 if(icon == mode_icons[i]) return i;
238         return TRANSFER_NORMAL;
239 }
240
241 void PatchBay::resize_event()
242 {
243         reposition_window(mwindow->theme->patchbay_x,
244                 mwindow->theme->patchbay_y,
245                 mwindow->theme->patchbay_w,
246                 mwindow->theme->patchbay_h);
247         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
248         update();
249         flash(0);
250 }
251
252 void PatchBay::resize_event(int x, int y, int w, int h)
253 {
254         reposition_window(x,
255                 y,
256                 w,
257                 h);
258         draw_top_background(get_parent(), 0, 0, w, h);
259         update();
260         flash(0);
261 }
262
263 int PatchBay::button_press_event()
264 {
265         int result = 0;
266 // Too much junk to support the wheel
267         return result;
268 }
269
270 int PatchBay::cursor_motion_event()
271 {
272         //int cursor_x = get_relative_cursor_x();
273         int cursor_y = get_relative_cursor_y();
274         int update_gui = 0;
275
276         if(drag_operation != Tracks::NONE)
277         {
278                 if(cursor_y >= 0 &&
279                         cursor_y < get_h())
280                 {
281 // Get track we're inside of
282                         for(Track *track = mwindow->edl->tracks->first;
283                                 track;
284                                 track = track->next)
285                         {
286                                 if( track->is_hidden() ) continue;
287                                 int y = track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
288                                 int h = track->vertical_span(mwindow->theme);
289                                 if(cursor_y >= y && cursor_y < y + h)
290                                 {
291                                         switch(drag_operation)
292                                         {
293                                                 case Tracks::PLAY:
294                                                         if(track->play != new_status)
295                                                         {
296                                                                 track->play = new_status;
297                                                                 mwindow->gui->unlock_window();
298                                                                 mwindow->restart_brender();
299                                                                 mwindow->sync_parameters(CHANGE_EDL);
300                                                                 mwindow->gui->lock_window();
301                                                                 update_gui = 1;
302                                                         }
303                                                         break;
304                                                 case Tracks::RECORD:
305                                                         if(track->armed != new_status)
306                                                         {
307                                                                 track->armed = new_status;
308                                                                 update_gui = 1;
309                                                         }
310                                                         break;
311                                                 case Tracks::GANG:
312                                                         if(track->ganged != new_status)
313                                                         {
314                                                                 track->ganged = new_status;
315                                                                 update_gui = 1;
316                                                         }
317                                                         break;
318                                                 case Tracks::DRAW:
319                                                         if(track->draw != new_status)
320                                                         {
321                                                                 track->draw = new_status;
322                                                                 update_gui = 1;
323                                                         }
324                                                         break;
325                                                 case Tracks::EXPAND:
326                                                         if(track->expand_view != new_status)
327                                                         {
328                                                                 track->expand_view = new_status;
329                                                                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
330                                                                 gui->draw_trackmovement();
331                                                                 update_gui = 0;
332                                                         }
333                                                         break;
334                                                 case Tracks::MUTE:
335                                                 {
336                                                         IntAuto *current = 0;
337                                                         Auto *keyframe = 0;
338                                                         double position = mwindow->edl->local_session->get_selectionstart(1);
339                                                         Autos *mute_autos = track->automation->autos[AUTOMATION_MUTE];
340
341                                                         current = (IntAuto*)mute_autos->get_prev_auto(PLAY_FORWARD,
342                                                                 keyframe);
343
344                                                         if(current->value != new_status)
345                                                         {
346
347 //                                                              mwindow->undo->update_undo_before(_("keyframe"), this);
348                                                                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
349
350                                                                 current->value = new_status;
351
352 //                                                              mwindow->undo->update_undo_after(_("keyframe"), LOAD_AUTOMATION);
353
354                                                                 mwindow->gui->unlock_window();
355                                                                 mwindow->restart_brender();
356                                                                 mwindow->sync_parameters(CHANGE_PARAMS);
357                                                                 mwindow->gui->lock_window();
358
359                                                                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
360                                                                 {
361                                                                         gui->draw_overlays(1);
362                                                                 }
363                                                                 update_gui = 1;
364                                                         }
365                                                         break;
366                                                 }
367                                         }
368                                 }
369                         }
370                 }
371         }
372
373         if(update_gui)
374         {
375                 gui->update_patchbay();
376         }
377         return 0;
378 }
379
380 void PatchBay::set_meter_format(int mode, int min, int max)
381 {
382         for(int i = 0; i < patches.total; i++)
383         {
384                 PatchGUI *patchgui = patches.values[i];
385                 if(patchgui->data_type == TRACK_AUDIO)
386                 {
387                         APatchGUI *apatchgui = (APatchGUI*)patchgui;
388                         if(apatchgui->meter)
389                         {
390                                 apatchgui->meter->change_format(mode, min, max);
391                         }
392                 }
393         }
394 }
395
396 void PatchBay::update_meters(ArrayList<double> *module_levels)
397 {
398         for(int level_number = 0, patch_number = 0;
399                 patch_number < patches.total && level_number < module_levels->total;
400                 patch_number++)
401         {
402                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
403
404                 if(patchgui->data_type == TRACK_AUDIO)
405                 {
406                         if(patchgui->meter)
407                         {
408                                 double level = module_levels->values[level_number];
409                                 patchgui->meter->update(level, level > 1);
410                         }
411
412                         level_number++;
413                 }
414         }
415 }
416
417 void PatchBay::reset_meters()
418 {
419         for(int patch_number = 0;
420                 patch_number < patches.total;
421                 patch_number++)
422         {
423                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
424                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
425                 {
426                         patchgui->meter->reset_over();
427                 }
428         }
429 }
430
431 void PatchBay::stop_meters()
432 {
433         for(int patch_number = 0;
434                 patch_number < patches.total;
435                 patch_number++)
436         {
437                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
438                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
439                 {
440                         patchgui->meter->reset();
441                 }
442         }
443 }
444
445
446 #define PATCH_X 3
447
448 int PatchBay::update()
449 {
450         int patch_count = 0;
451
452 // Every patch has a GUI regardless of whether or not it is visible.
453 // Make sure GUI's are allocated for every patch and deleted for non-existant
454 // patches.
455         for(Track *current = mwindow->edl->tracks->first; current; current = NEXT)
456         {
457                 if( current->is_hidden() ) continue;
458                 PatchGUI *patchgui = 0;
459                 int y = current->y_pixel;
460                 y -= mwindow->edl->local_session->track_start[pane->number];
461
462 //printf("PatchBay::update %d %d\n", __LINE__, y);
463                 if(patches.total > patch_count)
464                 {
465                         if(patches.values[patch_count]->track_id != current->get_id())
466                         {
467                                 delete patches.values[patch_count];
468
469                                 switch(current->data_type)
470                                 {
471                                         case TRACK_AUDIO:
472                                                 patchgui = patches.values[patch_count] = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
473                                                 break;
474                                         case TRACK_VIDEO:
475                                                 patchgui = patches.values[patch_count] = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
476                                                 break;
477                                         case TRACK_SUBTITLE:
478                                                 patchgui = patches.values[patch_count] = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
479                                                 break;
480                                 }
481                                 patchgui->create_objects();
482                         }
483                         else
484                         {
485                                 patches.values[patch_count]->update(PATCH_X, y);
486                         }
487                 }
488                 else
489                 {
490                         switch(current->data_type)
491                         {
492                                 case TRACK_AUDIO:
493                                         patchgui = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
494                                         break;
495                                 case TRACK_VIDEO:
496                                         patchgui = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
497                                         break;
498                                 case TRACK_SUBTITLE:
499                                         patchgui = new SPatchGUI(mwindow, this, (STrack*)current, PATCH_X, y);
500                                         break;
501                         }
502                         patches.append(patchgui);
503                         patchgui->create_objects();
504                 }
505                 ++patch_count;
506         }
507
508         while(patches.total > patch_count)
509         {
510                 delete patches.values[patches.total - 1];
511                 patches.remove_number(patches.total - 1);
512         }
513
514         show_window(0);
515         return 0;
516 }
517
518 void PatchBay::synchronize_faders(float change, int data_type, Track *skip)
519 {
520         for(Track *current = mwindow->edl->tracks->first;
521                 current;
522                 current = NEXT)
523         {
524                 if(current->data_type == data_type &&
525                         current->armed_gang(skip) &&
526                         current->is_armed() &&
527                         current != skip)
528                 {
529                         FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
530                         double position = mwindow->edl->local_session->get_selectionstart(1);
531
532
533                         FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_for_editing(position);
534
535                         float new_value = keyframe->get_value() + change;
536                         if(data_type == TRACK_AUDIO)
537                                 CLAMP(new_value,
538                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_AUDIO_FADE],
539                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_AUDIO_FADE]);
540                         else
541                                 CLAMP(new_value,
542                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_VIDEO_FADE],
543                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_VIDEO_FADE]);
544
545                         keyframe->set_value(new_value);
546
547                         PatchGUI *patch = get_patch_of(current);
548                         if(patch) patch->update(patch->x, patch->y);
549                 }
550         }
551 }
552
553 void PatchBay::synchronize_nudge(int64_t value, Track *skip)
554 {
555         Track *current = mwindow->edl->tracks->first;
556         for( ; current; current = NEXT ) {
557                 if( current->data_type == skip->data_type &&
558                     current->armed_gang(skip) && current->is_armed() &&
559                     current != skip ) {
560                         current->nudge = value;
561                         PatchGUI *patch = get_patch_of(current);
562                         if(patch) patch->update(patch->x, patch->y);
563                 }
564         }
565 }
566
567 PatchGUI* PatchBay::get_patch_of(Track *track)
568 {
569         for(int i = 0; i < patches.total; i++)
570         {
571                 if(patches.values[i]->track == track)
572                         return patches.values[i];
573         }
574         return 0;
575 }
576
577 int PatchBay::resize_event(int top, int bottom)
578 {
579         reposition_window(mwindow->theme->patchbay_x,
580                 mwindow->theme->patchbay_y,
581                 mwindow->theme->patchbay_w,
582                 mwindow->theme->patchbay_h);
583         return 0;
584 }
585
586