Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / patchbay.C
bloba8e38c66c86daf832eea800980886cb72c7be46b
1 #include "apatchgui.h"
2 #include "automation.h"
3 #include "floatauto.h"
4 #include "floatautos.h"
5 #include "clip.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "filexml.h"
9 #include "intauto.h"
10 #include "intautos.h"
11 #include "language.h"
12 #include "localsession.h"
13 #include "mainundo.h"
14 #include "mwindow.h"
15 #include "mwindowgui.h"
16 #include "patchbay.h"
17 #include "patchgui.h"
18 #include "mainsession.h"
19 #include "theme.h"
20 #include "track.h"
21 #include "trackcanvas.h"
22 #include "tracks.h"
23 #include "vpatchgui.h"
30 NudgePopup::NudgePopup(MWindow *mwindow, PatchBay *patchbay)
31  : BC_PopupMenu(0, 
32                 0, 
33                 0, 
34                 "", 
35                 0)
37         this->mwindow = mwindow;
38         this->patchbay = patchbay;
41 NudgePopup::~NudgePopup()
46 void NudgePopup::create_objects()
48         add_item(seconds_item = new NudgePopupSeconds(this));
49         add_item(native_item = new NudgePopupNative(this));
52 void NudgePopup::activate_menu(PatchGUI *gui)
54 // Set checked status
55         seconds_item->set_checked(mwindow->edl->session->nudge_seconds ? 1 : 0);
56         native_item->set_checked(mwindow->edl->session->nudge_seconds ? 0 : 1);
58 // Set native units to track format
59         native_item->set_text(gui->track->data_type == TRACK_AUDIO ? 
60                 (char*)"Samples" : 
61                 (char*)"Frames");
63 // Show it
64         BC_PopupMenu::activate_menu();
69 NudgePopupSeconds::NudgePopupSeconds(NudgePopup *popup)
70  : BC_MenuItem("Seconds")
72         this->popup = popup;
75 int NudgePopupSeconds::handle_event()
77         popup->mwindow->edl->session->nudge_seconds = 1;
78         popup->patchbay->update();
79         return 1;
86 NudgePopupNative::NudgePopupNative(NudgePopup *popup)
87  : BC_MenuItem("")
89         this->popup = popup;
92 int NudgePopupNative::handle_event()
94         popup->mwindow->edl->session->nudge_seconds = 0;
95         popup->patchbay->update();
96         return 1;
107 PatchBay::PatchBay(MWindow *mwindow, MWindowGUI *gui)
108  : BC_SubWindow(mwindow->theme->patchbay_x,
109         mwindow->theme->patchbay_y,
110         mwindow->theme->patchbay_w,
111         mwindow->theme->patchbay_h)
113         this->mwindow = mwindow;
114         this->gui = gui;
115         button_down = 0;
116         reconfigure_trigger = 0;
117         drag_operation = Tracks::NONE;
120 PatchBay::~PatchBay() 
125 int PatchBay::delete_all_patches()
127     patches.remove_all_objects();
128     return 0;
131 int PatchBay::create_objects()
133         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
134         flash();
136 // Create icons for mode types
137         mode_icons[TRANSFER_NORMAL] = new BC_Pixmap(this, 
138                 mwindow->theme->get_image("mode_normal"),
139                 PIXMAP_ALPHA);
140         mode_icons[TRANSFER_ADDITION] = new BC_Pixmap(this, 
141                 mwindow->theme->get_image("mode_add"),
142                 PIXMAP_ALPHA);
143         mode_icons[TRANSFER_SUBTRACT] = new BC_Pixmap(this, 
144                 mwindow->theme->get_image("mode_subtract"),
145                 PIXMAP_ALPHA);
146         mode_icons[TRANSFER_MULTIPLY] = new BC_Pixmap(this, 
147                 mwindow->theme->get_image("mode_multiply"),
148                 PIXMAP_ALPHA);
149         mode_icons[TRANSFER_DIVIDE] = new BC_Pixmap(this, 
150                 mwindow->theme->get_image("mode_divide"),
151                 PIXMAP_ALPHA);
152         mode_icons[TRANSFER_REPLACE] = new BC_Pixmap(this, 
153                 mwindow->theme->get_image("mode_replace"),
154                 PIXMAP_ALPHA);
155         mode_icons[TRANSFER_MAX] = new BC_Pixmap(this, 
156                 mwindow->theme->get_image("mode_max"),
157                 PIXMAP_ALPHA);
159         add_subwindow(nudge_popup = new NudgePopup(mwindow, this));
160         nudge_popup->create_objects();
162         return 0;
165 BC_Pixmap* PatchBay::mode_to_icon(int mode)
167         return mode_icons[mode];
170 int PatchBay::icon_to_mode(BC_Pixmap *icon)
172         for(int i = 0; i < TRANSFER_TYPES; i++)
173                 if(icon == mode_icons[i]) return i;
174         return TRANSFER_NORMAL;
177 void PatchBay::resize_event()
179         reposition_window(mwindow->theme->patchbay_x,
180                 mwindow->theme->patchbay_y,
181                 mwindow->theme->patchbay_w,
182                 mwindow->theme->patchbay_h);
183         draw_top_background(get_parent(), 0, 0, get_w(), get_h());
184         update();
185         flash();
188 int PatchBay::button_press_event()
190         int result = 0;
191 // Too much junk to support the wheel
192         return result;
196 Track *PatchBay::is_over_track()     // called from mwindow
198         int cursor_x = get_relative_cursor_x();
199         int cursor_y = get_relative_cursor_y();
200         Track *over_track = 0;
202         if(get_cursor_over_window() &&
203                 cursor_x >= 0 && 
204                 cursor_y >= 0 && 
205                 cursor_x < get_w() && 
206                 cursor_y < get_h())
207         {
208 // Get track we're inside of
209                 for(Track *track = mwindow->edl->tracks->first;
210                         track;
211                         track = track->next)
212                 {
213                         int y = track->y_pixel;
214                         int h = track->vertical_span(mwindow->theme);
215                         if(cursor_y >= y && cursor_y < y + h)
216                         {       
217                                 over_track = track;
218                         }
219                 }
220         }                               
221         return (over_track);
225 int PatchBay::cursor_motion_event()
227         int cursor_x = get_relative_cursor_x();
228         int cursor_y = get_relative_cursor_y();
229         int update_gui = 0;
231         if(drag_operation != Tracks::NONE)
232         {
233                 if(cursor_y >= 0 &&
234                         cursor_y < get_h())
235                 {
236 // Get track we're inside of
237                         for(Track *track = mwindow->edl->tracks->first;
238                                 track;
239                                 track = track->next)
240                         {
241                                 int y = track->y_pixel;
242                                 int h = track->vertical_span(mwindow->theme);
243                                 if(cursor_y >= y && cursor_y < y + h)
244                                 {
245                                         switch(drag_operation)
246                                         {
247                                                 case Tracks::PLAY:
248                                                         if(track->play != new_status)
249                                                         {
250                                                                 track->play = new_status;
251                                                                 mwindow->gui->unlock_window();
252                                                                 mwindow->restart_brender();
253                                                                 mwindow->sync_parameters(CHANGE_EDL);
254                                                                 mwindow->gui->lock_window();
255                                                                 update_gui = 1;
256                                                         }
257                                                         break;
258                                                 case Tracks::RECORD:
259                                                         if(track->record != new_status)
260                                                         {
261                                                                 track->record = new_status;
262                                                                 update_gui = 1;
263                                                         }
264                                                         break;
265                                                 case Tracks::GANG:
266                                                         if(track->gang != new_status)
267                                                         {
268                                                                 track->gang = new_status;
269                                                                 update_gui = 1;
270                                                         }
271                                                         break;
272                                                 case Tracks::DRAW:
273                                                         if(track->draw != new_status)
274                                                         {
275                                                                 track->draw = new_status;
276                                                                 update_gui = 1;
277                                                         }
278                                                         break;
279                                                 case Tracks::EXPAND:
280                                                         if(track->expand_view != new_status)
281                                                         {
282                                                                 track->expand_view = new_status;
283                                                                 mwindow->trackmovement(mwindow->edl->local_session->track_start);
284                                                                 update_gui = 0;
285                                                         }
286                                                         break;
287                                                 case Tracks::MUTE:
288                                                 {
289                                                         IntAuto *current = 0;
290                                                         Auto *keyframe = 0;
291                                                         double position = mwindow->edl->local_session->get_selectionstart(1);
292                                                         Autos *mute_autos = track->automation->autos[AUTOMATION_MUTE];
294                                                         current = (IntAuto*)mute_autos->get_prev_auto(PLAY_FORWARD, 
295                                                                 keyframe);
297                                                         if(current->value != new_status)
298                                                         {
300                                                                 current = (IntAuto*)mute_autos->get_auto_for_editing(position);
302                                                                 current->value = new_status;
304                                                                 mwindow->undo->update_undo(_("keyframe"), LOAD_AUTOMATION);
306                                                                 mwindow->gui->unlock_window();
307                                                                 mwindow->restart_brender();
308                                                                 mwindow->sync_parameters(CHANGE_PARAMS);
309                                                                 mwindow->gui->lock_window();
311                                                                 if(mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE])
312                                                                 {
313                                                                         mwindow->gui->canvas->draw_overlays();
314                                                                         mwindow->gui->canvas->flash();
315                                                                 }
316                                                                 update_gui = 1;
317                                                         }
318                                                         break;
319                                                 }
320                                         }
321                                 }
322                         }
323                 }
324         }
326         if(update_gui)
327         {
328                 update();
329         }
330         return 0;
333 void PatchBay::change_meter_format(int mode, int min, int max)
335         for(int i = 0; i < patches.total; i++)
336         {
337                 PatchGUI *patchgui = patches.values[i];
338                 if(patchgui->data_type == TRACK_AUDIO)
339                 {
340                         APatchGUI *apatchgui = (APatchGUI*)patchgui;
341                         if(apatchgui->meter)
342                         {
343                                 apatchgui->meter->change_format(mode, min, max);
344                         }
345                 }
346         }
349 void PatchBay::update_meters(ArrayList<double> *module_levels)
351         for(int level_number = 0, patch_number = 0;
352                 patch_number < patches.total && level_number < module_levels->total;
353                 patch_number++)
354         {
355                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
357                 if(patchgui->data_type == TRACK_AUDIO)
358                 {
359                         if(patchgui->meter)
360                         {
361                                 double level = module_levels->values[level_number];
362                                 patchgui->meter->update(level, level > 1);
363                         }
365                         level_number++;
366                 }
367         }
370 void PatchBay::reset_meters()
372         for(int patch_number = 0;
373                 patch_number < patches.total;
374                 patch_number++)
375         {
376                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
377                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
378                 {
379                         patchgui->meter->reset_over();
380                 }
381         }
384 void PatchBay::stop_meters()
386         for(int patch_number = 0;
387                 patch_number < patches.total;
388                 patch_number++)
389         {
390                 APatchGUI *patchgui = (APatchGUI*)patches.values[patch_number];
391                 if(patchgui->data_type == TRACK_AUDIO && patchgui->meter)
392                 {
393                         patchgui->meter->reset();
394                 }
395         }
399 #define PATCH_X 3
401 int PatchBay::update()
403         int patch_count = 0;
405 // Every patch has a GUI regardless of whether or not it is visible.
406 // Make sure GUI's are allocated for every patch and deleted for non-existant
407 // patches.
408         for(Track *current = mwindow->edl->tracks->first;
409                 current;
410                 current = NEXT, patch_count++)
411         {
412                 PatchGUI *patchgui;
413                 int y = current->y_pixel;
415                 if(patches.total > patch_count)
416                 {
417                         if(patches.values[patch_count]->track_id != current->get_id())
418                         {
419                                 delete patches.values[patch_count];
421                                 switch(current->data_type)
422                                 {
423                                         case TRACK_AUDIO:
424                                                 patchgui = patches.values[patch_count] = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
425                                                 break;
426                                         case TRACK_VIDEO:
427                                                 patchgui = patches.values[patch_count] = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
428                                                 break;
429                                 }
430                                 patchgui->create_objects();
431                         }
432                         else
433                         {
434                                 patches.values[patch_count]->update(PATCH_X, y);
435                         }
436                 }
437                 else
438                 {
439                         switch(current->data_type)
440                         {
441                                 case TRACK_AUDIO:
442                                         patchgui = new APatchGUI(mwindow, this, (ATrack*)current, PATCH_X, y);
443                                         break;
444                                 case TRACK_VIDEO:
445                                         patchgui = new VPatchGUI(mwindow, this, (VTrack*)current, PATCH_X, y);
446                                         break;
447                         }
448                         patches.append(patchgui);
449                         patchgui->create_objects();
450                 }
451         }
453         while(patches.total > patch_count)
454         {
455                 delete patches.values[patches.total - 1];
456                 patches.remove_number(patches.total - 1);
457         }
459         return 0;
462 void PatchBay::synchronize_faders(float change, int data_type, Track *skip)
464         for(Track *current = mwindow->edl->tracks->first;
465                 current;
466                 current = NEXT)
467         {
468                 if(current->data_type == data_type &&
469                         current->gang && 
470                         current->record && 
471                         current != skip)
472                 {
473                         FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
474                         double position = mwindow->edl->local_session->get_selectionstart(1);
477                         FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_for_editing(position);
479                         keyframe->value += change;
480                         if(data_type == TRACK_AUDIO)
481                                 CLAMP(keyframe->value, 
482                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_AUDIO_FADE],
483                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_AUDIO_FADE]);
484                         else
485                                 CLAMP(keyframe->value, 
486                                       mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_VIDEO_FADE],
487                                       mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_VIDEO_FADE]);
489                         PatchGUI *patch = get_patch_of(current);
490                         if(patch) patch->update(patch->x, patch->y);
491                 }
492         }
495 void PatchBay::synchronize_nudge(int64_t value, Track *skip)
497         for(Track *current = mwindow->edl->tracks->first;
498                 current;
499                 current = NEXT)
500         {
501                 if(current->data_type == skip->data_type &&
502                         current->gang &&
503                         current->record &&
504                         current != skip)
505                 {
506                         current->nudge = value;
507                         PatchGUI *patch = get_patch_of(current);
508                         if(patch) patch->update(patch->x, patch->y);
509                 }
510         }
513 PatchGUI* PatchBay::get_patch_of(Track *track)
515         for(int i = 0; i < patches.total; i++)
516         {
517                 if(patches.values[i]->track == track)
518                         return patches.values[i];
519         }
520         return 0;
523 int PatchBay::resize_event(int top, int bottom)
525         reposition_window(mwindow->theme->patchbay_x,
526                 mwindow->theme->patchbay_y,
527                 mwindow->theme->patchbay_w,
528                 mwindow->theme->patchbay_h);
529         return 0;
534 //      Local Variables:
535 //      mode: C++
536 //      c-file-style: "linux"
537 //      End: