Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / vpatchgui.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 "autoconf.h"
23 #include "automation.h"
24 #include "edl.h"
25 #include "edlsession.h"
26 #include "floatauto.h"
27 #include "floatautos.h"
28 #include "gwindowgui.h"
29 #include "intauto.h"
30 #include "intautos.h"
31 #include "keys.h"
32 #include "language.h"
33 #include "localsession.h"
34 #include "mainsession.h"
35 #include "mainundo.h"
36 #include "mwindow.h"
37 #include "mwindowgui.h"
38 #include "overlayframe.inc"
39 #include "patchbay.h"
40 #include "theme.h"
41 #include "trackcanvas.h"
42 #include "vpatchgui.h"
43 #include "vtrack.h"
44 #include "vwindow.h"
45
46 #include <string.h>
47
48
49 VPatchGUI::VPatchGUI(MWindow *mwindow, PatchBay *patchbay, VTrack *track, int x, int y)
50  : PatchGUI(mwindow, patchbay, track, x, y)
51 {
52         data_type = TRACK_VIDEO;
53         this->vtrack = track;
54         mode = 0;
55         fade = 0;
56 }
57
58 VPatchGUI::~VPatchGUI()
59 {
60         if( fade ) delete fade;
61         if( mode ) delete mode;
62 }
63
64 void VPatchGUI::create_objects()
65 {
66         update(x, y);
67 }
68
69 int VPatchGUI::reposition(int x, int y)
70 {
71         //int x1 = 0;
72         int y1 = PatchGUI::reposition(x, y);
73
74         if( fade )
75                 fade->reposition_window(fade->get_x(), y1+y);
76         y1 += mwindow->theme->fade_h;
77         if( mix )
78                 mix->reposition_window(mix->get_x(), y1+y);
79         if( mode )
80                 mode->reposition_window(mode->get_x(), y1+y);
81         if( nudge )
82                 nudge->reposition_window(nudge->get_x(), y1+y);
83         y1 += mwindow->theme->mode_h;
84         return y1;
85 }
86
87 int VPatchGUI::update(int x, int y)
88 {
89         int h = track->vertical_span(mwindow->theme);
90         int x1 = 0;
91         int y1 = PatchGUI::update(x, y);
92
93         int y2 = y1 + mwindow->theme->fade_h;
94         if( fade ) {
95                 if( h < y2 ) {
96                         delete fade;  fade = 0;
97                 }
98                 else {
99                         fade->update(fade->get_w(), mwindow->get_float_auto(this, AUTOMATION_FADE)->get_value(),
100                                      mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_VIDEO_FADE],
101                                      mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_VIDEO_FADE]);
102                 }
103         }
104         else if( h >= y2 ) {
105                 int64_t v = mwindow->get_float_auto(this, AUTOMATION_FADE)->get_value();
106                 patchbay->add_subwindow(fade = new VFadePatch(this, x1+x, y1+y,
107                         patchbay->get_w() - 10, v));
108         }
109         y1 = y2;
110
111         y2 = y1 + mwindow->theme->mode_h;
112         if( mode ) {
113                 if( h < y2 ) {
114                         delete mix;    mix = 0;
115                         delete mode;   mode = 0;
116                         delete nudge;  nudge = 0;
117                 }
118                 else {
119                         if( mwindow->session->selected_zwindow >= 0 ) {
120                                 int v = mwindow->mixer_track_active(track);
121                                 mix->update(v);
122                         }
123                         mode->update(mwindow->get_int_auto(this, AUTOMATION_MODE)->value);
124                         nudge->update();
125                 }
126         }
127         else if( h >= y2 ) {
128                 patchbay->add_subwindow(mix = new VMixPatch(mwindow, this, x1+x, y1+y+5));
129                 x1 += mix->get_w();
130                 patchbay->add_subwindow(mode = new VModePatch(mwindow, this, x1+x, y1+y));
131                 mode->create_objects();
132                 x1 += mode->get_w();
133                 patchbay->add_subwindow(nudge = new NudgePatch(mwindow, this, x1+x, y1+y,
134                         patchbay->get_w() - x1-x - 10));
135         }
136         y1 = y2;
137
138         return y1;
139 }
140
141 VFadePatch::VFadePatch(VPatchGUI *patch, int x, int y, int w, int64_t v)
142  : BC_ISlider(x, y, 0, w, w,
143                 patch->mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_VIDEO_FADE],
144                 patch->mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_VIDEO_FADE],
145                 v)
146 {
147         this->patch = patch;
148 }
149
150 void VPatchGUI::update_faders(float v)
151 {
152         if( fade )
153                 fade->update(v);
154
155         change_source = 1;
156         double position = mwindow->edl->local_session->get_selectionstart(1);
157         Autos *fade_autos = vtrack->automation->autos[AUTOMATION_FADE];
158         int need_undo = !fade_autos->auto_exists_for_editing(position);
159
160         mwindow->undo->update_undo_before(_("fade"), need_undo ? 0 : this);
161         FloatAuto *current = (FloatAuto*)fade_autos->get_auto_for_editing(position);
162         float change = v - current->get_value();
163         current->set_value(v);
164
165         if( track->gang && track->record )
166                 patchbay->synchronize_faders(change, TRACK_AUDIO, track);
167         mwindow->undo->update_undo_after(_("fade"), LOAD_AUTOMATION);
168         change_source = 0;
169
170         mwindow->sync_parameters(CHANGE_PARAMS);
171
172         if( mwindow->edl->session->auto_conf->autos[AUTOMATION_FADE] ) {
173                 mwindow->gui->draw_overlays(1);
174         }
175 }
176
177 int VFadePatch::handle_event()
178 {
179         if( shift_down() ) {
180                 update(100);
181                 set_tooltip(get_caption());
182         }
183         patch->update_faders(get_value());
184         return 1;
185 }
186
187 VKeyFadePatch::VKeyFadePatch(MWindow *mwindow, VPatchGUI *patch, int x, int y)
188  : BC_SubWindow(x,y, 200,20, GWindowGUI::auto_colors[AUTOMATION_FADE])
189 {
190         this->mwindow = mwindow;
191         this->patch = patch;
192 }
193
194 void VKeyFadePatch::create_objects()
195 {
196         int x = 0, y = 0;
197         int64_t v = mwindow->get_float_auto(patch, AUTOMATION_FADE)->get_value();
198         add_subwindow(vkey_fade_text = new VKeyFadeText(this, x, y, 64, v));
199         x += vkey_fade_text->get_w();
200         VFrame **lok_images = mwindow->theme->get_image_set("lok");
201         int w1 = get_w() - x - lok_images[0]->get_w();
202         add_subwindow(vkey_fade_slider = new VKeyFadeSlider(this, x, y, w1, v));
203         x += vkey_fade_slider->get_w();
204         add_subwindow(vkey_fade_ok = new VKeyFadeOK(this, x, y, lok_images));
205         activate();
206         show_window();
207 }
208
209 void VKeyFadePatch::update(int64_t v)
210 {
211         vkey_fade_text->update(v);
212         vkey_fade_slider->update(v);
213         patch->update_faders(v);
214 }
215
216 VKeyFadeOK::VKeyFadeOK(VKeyFadePatch *vkey_fade_patch, int x, int y, VFrame **images)
217  : BC_Button(x, y, images)
218 {
219         this->vkey_fade_patch = vkey_fade_patch;
220 }
221
222 int VKeyFadeOK::handle_event()
223 {
224         MWindowGUI *mgui = vkey_fade_patch->mwindow->gui;
225         delete mgui->keyvalue_popup;
226         mgui->keyvalue_popup = 0;
227         return 1;
228 }
229
230 VKeyFadeText::VKeyFadeText(VKeyFadePatch *vkey_fade_patch, int x, int y, int w, int64_t v)
231  : BC_TextBox(x, y, w, 1, v, 1, MEDIUMFONT)
232 {
233         this->vkey_fade_patch = vkey_fade_patch;
234 }
235
236 int VKeyFadeText::handle_event()
237 {
238         int64_t v = atoi(get_text());
239         vkey_fade_patch->update(v);
240         return get_keypress() != RETURN ? 1 :
241                 vkey_fade_patch->vkey_fade_ok->handle_event();
242 }
243
244 VKeyFadeSlider::VKeyFadeSlider(VKeyFadePatch *vkey_fade_patch,
245         int x, int y, int w, int64_t v)
246  : VFadePatch(vkey_fade_patch->patch, x,y, w, v)
247 {
248         this->vkey_fade_patch = vkey_fade_patch;
249 }
250
251 int VKeyFadeSlider::handle_event()
252 {
253         int64_t v = get_value();
254         vkey_fade_patch->update(v);
255         return 1;
256 }
257
258
259 VModePatch::VModePatch(MWindow *mwindow, VPatchGUI *patch, int x, int y)
260  : BC_PopupMenu(x, y, patch->patchbay->mode_icons[0]->get_w() + 20,
261         "", 1, mwindow->theme->get_image_set("mode_popup", 0), 10)
262 {
263         this->mwindow = mwindow;
264         this->patch = patch;
265         this->mode = mwindow->get_int_auto(patch, AUTOMATION_MODE)->value;
266         set_icon(patch->patchbay->mode_to_icon(this->mode));
267         set_tooltip(_("Overlay mode"));
268 }
269
270 VModePatch::VModePatch(MWindow *mwindow, VPatchGUI *patch)
271  : BC_PopupMenu(0, 0, 0, "", 0)
272 {
273         this->mwindow = mwindow;
274         this->patch = patch;
275         this->mode = mwindow->get_int_auto(patch, AUTOMATION_MODE)->value;
276 }
277
278
279 int VModePatch::handle_event()
280 {
281 // Set menu items
282 //      for( int i = 0; i < total_items(); i++ )
283 //      {
284 //              VModePatchItem *item = (VModePatchItem*)get_item(i);
285 //              if( item->mode == mode )
286 //                      item->set_checked(1);
287 //              else
288 //                      item->set_checked(0);
289 //      }
290         update(mode);
291
292 // Set keyframe
293         IntAuto *current;
294         double position = mwindow->edl->local_session->get_selectionstart(1);
295         Autos *mode_autos = patch->vtrack->automation->autos[AUTOMATION_MODE];
296         int need_undo = !mode_autos->auto_exists_for_editing(position);
297
298         mwindow->undo->update_undo_before(_("mode"), need_undo ? 0 : this);
299
300         current = (IntAuto*)mode_autos->get_auto_for_editing(position);
301         current->value = mode;
302
303         mwindow->undo->update_undo_after(_("mode"), LOAD_AUTOMATION);
304
305         mwindow->sync_parameters(CHANGE_PARAMS);
306
307         if( mwindow->edl->session->auto_conf->autos[AUTOMATION_MODE] ) {
308                 mwindow->gui->draw_overlays(1);
309         }
310         mwindow->session->changes_made = 1;
311         return 1;
312 }
313
314 void VModePatch::create_objects()
315 {
316         VModePatchItem *mode_item;
317         VModePatchSubMenu *submenu;
318         add_item(mode_item = new VModePatchItem(this, mode_to_text(TRANSFER_NORMAL),  TRANSFER_NORMAL));
319         add_item(mode_item = new VModePatchItem(this, _("Arithmetic..."), -1));
320         mode_item->add_submenu(submenu = new VModePatchSubMenu(mode_item));
321         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_ADDITION), TRANSFER_ADDITION));
322         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SUBTRACT), TRANSFER_SUBTRACT));
323         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DIVIDE),   TRANSFER_DIVIDE));
324         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_MULTIPLY), TRANSFER_MULTIPLY));
325         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_REPLACE),  TRANSFER_REPLACE));
326         add_item(mode_item = new VModePatchItem(this, _("PorterDuff..."), -1));
327         mode_item->add_submenu(submenu = new VModePatchSubMenu(mode_item));
328         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DST),      TRANSFER_DST));
329         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DST_ATOP), TRANSFER_DST_ATOP));
330         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DST_IN),   TRANSFER_DST_IN));
331         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DST_OUT),  TRANSFER_DST_OUT));
332         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DST_OVER), TRANSFER_DST_OVER));
333         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SRC),      TRANSFER_SRC));
334         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SRC_ATOP), TRANSFER_SRC_ATOP));
335         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SRC_IN),   TRANSFER_SRC_IN));
336         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SRC_OUT),  TRANSFER_SRC_OUT));
337         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SRC_OVER), TRANSFER_SRC_OVER));
338         add_item(mode_item = new VModePatchItem(this, _("Logical..."), -1));
339         mode_item->add_submenu(submenu = new VModePatchSubMenu(mode_item));
340         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_MIN),      TRANSFER_MIN));
341         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_MAX),      TRANSFER_MAX));
342         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DARKEN),   TRANSFER_DARKEN));
343         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_LIGHTEN),  TRANSFER_LIGHTEN));
344         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_AND),      TRANSFER_AND));
345         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_OR),       TRANSFER_OR));
346         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_XOR),      TRANSFER_XOR));
347         add_item(mode_item = new VModePatchItem(this, _("Graphic Art..."), -1));
348         mode_item->add_submenu(submenu = new VModePatchSubMenu(mode_item));
349         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_OVERLAY),  TRANSFER_OVERLAY));
350         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SCREEN),   TRANSFER_SCREEN));
351         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_BURN),     TRANSFER_BURN));
352         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DODGE),    TRANSFER_DODGE));
353         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_DIFFERENCE),TRANSFER_DIFFERENCE));
354         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_HARDLIGHT),TRANSFER_HARDLIGHT));
355         submenu->add_submenuitem(new VModeSubMenuItem(submenu, mode_to_text(TRANSFER_SOFTLIGHT),TRANSFER_SOFTLIGHT));
356 }
357
358 void VModePatch::update(int mode)
359 {
360         set_icon(patch->patchbay->mode_to_icon(mode));
361         for( int i = 0; i < total_items(); i++ ) {
362                 VModePatchItem *item = (VModePatchItem*)get_item(i);
363                 item->set_checked(item->mode == mode);
364                 VModePatchSubMenu *submenu = (VModePatchSubMenu *)item->get_submenu();
365                 if( !submenu ) continue;
366                 int n = submenu->total_items();
367                 for( int j=0; j<n; ++j ) {
368                         VModePatchItem *subitem = (VModePatchItem*)submenu->get_item(j);
369                         subitem->set_checked(subitem->mode == mode);
370                 }
371         }
372 }
373
374
375 const char* VModePatch::mode_to_text(int mode)
376 {
377         switch( mode ) {
378         case TRANSFER_NORMAL:           return _("Normal");
379         case TRANSFER_ADDITION:         return _("Addition");
380         case TRANSFER_SUBTRACT:         return _("Subtract");
381         case TRANSFER_MULTIPLY:         return _("Multiply");
382         case TRANSFER_DIVIDE:           return _("Divide");
383         case TRANSFER_REPLACE:          return _("Replace");
384         case TRANSFER_MAX:              return _("Max");
385         case TRANSFER_MIN:              return _("Min");
386         case TRANSFER_DARKEN:           return _("Darken");
387         case TRANSFER_LIGHTEN:          return _("Lighten");
388         case TRANSFER_DST:              return _("Dst");
389         case TRANSFER_DST_ATOP:         return _("DstAtop");
390         case TRANSFER_DST_IN:           return _("DstIn");
391         case TRANSFER_DST_OUT:          return _("DstOut");
392         case TRANSFER_DST_OVER:         return _("DstOver");
393         case TRANSFER_SRC:              return _("Src");
394         case TRANSFER_SRC_ATOP:         return _("SrcAtop");
395         case TRANSFER_SRC_IN:           return _("SrcIn");
396         case TRANSFER_SRC_OUT:          return _("SrcOut");
397         case TRANSFER_SRC_OVER:         return _("SrcOver");
398         case TRANSFER_AND:              return _("AND");
399         case TRANSFER_OR:               return _("OR");
400         case TRANSFER_XOR:              return _("XOR");
401         case TRANSFER_OVERLAY:          return _("Overlay");
402         case TRANSFER_SCREEN:           return _("Screen");
403         case TRANSFER_BURN:             return _("Burn");
404         case TRANSFER_DODGE:            return _("Dodge");
405         case TRANSFER_HARDLIGHT:        return _("Hardlight");
406         case TRANSFER_SOFTLIGHT:        return _("Softlight");
407         case TRANSFER_DIFFERENCE:       return _("Difference");
408         }
409         return _("Normal");
410 }
411
412
413
414 VModePatchItem::VModePatchItem(VModePatch *popup, const char *text, int mode)
415  : BC_MenuItem(text)
416 {
417         this->popup = popup;
418         this->mode = mode;
419         if( this->mode == popup->mode ) set_checked(1);
420 }
421
422 int VModePatchItem::handle_event()
423 {
424         if( mode >= 0 ) {
425                 popup->mode = mode;
426 //              popup->set_icon(popup->patch->patchbay->mode_to_icon(mode));
427                 popup->handle_event();
428         }
429         return 1;
430 }
431
432 VModePatchSubMenu::VModePatchSubMenu(VModePatchItem *mode_item)
433 {
434         this->mode_item = mode_item;
435 }
436 VModePatchSubMenu::~VModePatchSubMenu()
437 {
438 }
439
440 VModeSubMenuItem::VModeSubMenuItem(VModePatchSubMenu *submenu, const char *text, int mode)
441  : BC_MenuItem(text)
442 {
443         this->submenu = submenu;
444         this->mode = mode;
445         VModePatch *popup = submenu->mode_item->popup;
446         if( this->mode == popup->mode ) set_checked(1);
447 }
448 VModeSubMenuItem::~VModeSubMenuItem()
449 {
450 }
451
452 int VModeSubMenuItem::handle_event()
453 {
454         VModePatch *popup = submenu->mode_item->popup;
455         popup->mode = mode;
456 //      popup->set_icon(popup->patch->patchbay->mode_to_icon(mode));
457         popup->handle_event();
458         return 1;
459 }
460
461
462 VKeyModePatch::VKeyModePatch(MWindow *mwindow, VPatchGUI *patch)
463  : VModePatch(mwindow, patch)
464 {
465 }
466
467 int VKeyModePatch::handle_event()
468 {
469         int ret = VModePatch::handle_event();
470         VModePatch *mode = patch->mode;
471         if( mode )
472                 mode->update(this->mode);
473         return ret;
474 }
475
476
477 VMixPatch::VMixPatch(MWindow *mwindow, VPatchGUI *patch, int x, int y)
478  : MixPatch(mwindow, patch, x, y)
479 {
480         set_tooltip(_("Mixer"));
481 }
482
483 VMixPatch::~VMixPatch()
484 {
485 }
486