mask mousewheel segv bug, mask opengl sw fallback read to ram, fix tiff config withou...
[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                                 int y = track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
287                                 int h = track->vertical_span(mwindow->theme);
288                                 if(cursor_y >= y && cursor_y < y + h)
289                                 {
290                                         switch(drag_operation)
291                                         {
292                                                 case Tracks::PLAY:
293                                                         if(track->play != new_status)
294                                                         {
295                                                                 track->play = new_status;
296                                                                 mwindow->gui->unlock_window();
297                                                                 mwindow->restart_brender();
298                                                                 mwindow->sync_parameters(CHANGE_EDL);
299                                                                 mwindow->gui->lock_window();
300                                                                 update_gui = 1;
301                                                         }
302                                                         break;
303                                                 case Tracks::RECORD:
304                                                         if(track->record != new_status)
305                                                         {
306                                                                 track->record = new_status;
307                                                                 update_gui = 1;
308                                                         }
309                                                         break;
310                                                 case Tracks::GANG:
311                                                         if(track->gang != new_status)
312                                                         {
313                                                                 track->gang = new_status;
314                                                                 update_gui = 1;
315                                                         }
316                                                         break;
317                                                 case Tracks::DRAW:
318                                                         if(track->draw != new_status)
319                                                         {
320                                                                 track->draw = new_status;
321                                                                 update_gui = 1;
322                                                         }
323                                                         break;
324                                                 case Tracks::EXPAND:
325                                                         if(track->expand_view != new_status)
326                                                         {
327                                                                 track->expand_view = new_status;
328                                                                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
329                                                                 gui->draw_trackmovement();
330                                                                 update_gui = 0;
331                                                         }
332                                                         break;
333                                                 case Tracks::MUTE:
334                                                 {
335                                                         IntAuto *current = 0;
336                                                         Auto *keyframe = 0;
337                                                         double position = mwindow->edl->local_session->get_selectionstart(1);
338                                                         Autos *mute_autos = track->automation->autos[AUTOMATION_MUTE];
339
340                                                         current = (IntAuto*)mute_autos->get_prev_auto(PLAY_FORWARD,
341                                                                 keyframe);
342
343                                                         if(current->value != new_status)
344                                                         {
345
346 //                                                              mwindow->undo->update_undo_before(_("keyframe"), this);
347                                                                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
348
349                                                                 current->value = new_status;
350
351 //                                                              mwindow->undo->update_undo_after(_("keyframe"), LOAD_AUTOMATION);
352
353                                                                 mwindow->gui->unlock_window();
354                                                                 mwindow->restart_brender();
355                                                                 mwindow->sync_parameters(CHANGE_PARAMS);
356                                                                 mwindow->gui->lock_window();
357
358                                                                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
359                                                                 {
360                                                                         gui->draw_overlays(1);
361                                                                 }
362                                                                 update_gui = 1;
363                                                         }
364                                                         break;
365                                                 }
366                                         }
367                                 }
368                         }
369                 }
370         }
371
372         if(update_gui)
373         {
374                 gui->update_patchbay();
375         }
376         return 0;
377 }
378
379 void PatchBay::set_meter_format(int mode, int min, int max)
380 {
381         for(int i = 0; i < patches.total; i++)
382         {
383                 PatchGUI *patchgui = patches.values[i];
384                 if(patchgui->data_type == TRACK_AUDIO)
385                 {
386                         APatchGUI *apatchgui = (APatchGUI*)patchgui;
387                         if(apatchgui->meter)
388                         {
389                                 apatchgui->meter->change_format(mode, min, max);
390                         }
391                 }
392         }
393 }
394
395 void PatchBay::update_meters(ArrayList<double> *module_levels)
396 {
397         for(int level_number = 0, patch_number = 0;
398                 patch_number < patches.total && level_number < module_levels->total;
399                 patch_number++)
400         {
401                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
402
403                 if(patchgui->data_type == TRACK_AUDIO)
404                 {
405                         if(patchgui->meter)
406                         {
407                                 double level = module_levels->values[level_number];
408                                 patchgui->meter->update(level, level > 1);
409                         }
410
411                         level_number++;
412                 }
413         }
414 }
415
416 void PatchBay::reset_meters()
417 {
418         for(int patch_number = 0;
419                 patch_number < patches.total;
420                 patch_number++)
421         {
422                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
423                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
424                 {
425                         patchgui->meter->reset_over();
426                 }
427         }
428 }
429
430 void PatchBay::stop_meters()
431 {
432         for(int patch_number = 0;
433                 patch_number < patches.total;
434                 patch_number++)
435         {
436                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
437                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
438                 {
439                         patchgui->meter->reset();
440                 }
441         }
442 }
443
444
445 #define PATCH_X 3
446
447 int PatchBay::update()
448 {
449         int patch_count = 0;
450
451 // Every patch has a GUI regardless of whether or not it is visible.
452 // Make sure GUI's are allocated for every patch and deleted for non-existant
453 // patches.
454         for(Track *current = mwindow->edl->tracks->first;
455                 current;
456                 current = NEXT, patch_count++)
457         {
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         }
506
507         while(patches.total > patch_count)
508         {
509                 delete patches.values[patches.total - 1];
510                 patches.remove_number(patches.total - 1);
511         }
512
513         show_window(0);
514         return 0;
515 }
516
517 void PatchBay::synchronize_faders(float change, int data_type, Track *skip)
518 {
519         for(Track *current = mwindow->edl->tracks->first;
520                 current;
521                 current = NEXT)
522         {
523                 if(current->data_type == data_type &&
524                         current->gang &&
525                         current->record &&
526                         current != skip)
527                 {
528                         FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
529                         double position = mwindow->edl->local_session->get_selectionstart(1);
530
531
532                         FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_for_editing(position);
533
534                         float new_value = keyframe->get_value() + change;
535                         if(data_type == TRACK_AUDIO)
536                                 CLAMP(new_value,
537                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_AUDIO_FADE],
538                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_AUDIO_FADE]);
539                         else
540                                 CLAMP(new_value,
541                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_VIDEO_FADE],
542                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_VIDEO_FADE]);
543
544                         keyframe->set_value(new_value);
545
546                         PatchGUI *patch = get_patch_of(current);
547                         if(patch) patch->update(patch->x, patch->y);
548                 }
549         }
550 }
551
552 void PatchBay::synchronize_nudge(int64_t value, Track *skip)
553 {
554         for(Track *current = mwindow->edl->tracks->first;
555                 current;
556                 current = NEXT)
557         {
558                 if(current->data_type == skip->data_type &&
559                         current->gang &&
560                         current->record &&
561                         current != skip)
562                 {
563                         current->nudge = value;
564                         PatchGUI *patch = get_patch_of(current);
565                         if(patch) patch->update(patch->x, patch->y);
566                 }
567         }
568 }
569
570 PatchGUI* PatchBay::get_patch_of(Track *track)
571 {
572         for(int i = 0; i < patches.total; i++)
573         {
574                 if(patches.values[i]->track == track)
575                         return patches.values[i];
576         }
577         return 0;
578 }
579
580 int PatchBay::resize_event(int top, int bottom)
581 {
582         reposition_window(mwindow->theme->patchbay_x,
583                 mwindow->theme->patchbay_y,
584                 mwindow->theme->patchbay_w,
585                 mwindow->theme->patchbay_h);
586         return 0;
587 }
588
589