no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / apatchgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "atrack.h"
24 #include "autoconf.h"
25 #include "automation.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "floatauto.h"
29 #include "floatautos.h"
30 #include "gwindowgui.h"
31 #include "intauto.h"
32 #include "intautos.h"
33 #include "keys.h"
34 #include "language.h"
35 #include "localsession.h"
36 #include "mainsession.h"
37 #include "mainundo.h"
38 #include "mwindow.h"
39 #include "mwindowgui.h"
40 #include "panauto.h"
41 #include "panautos.h"
42 #include "patchbay.h"
43 #include "theme.h"
44 #include "trackcanvas.h"
45 #include "zwindow.h"
46
47 APatchGUI::APatchGUI(MWindow *mwindow, PatchBay *patchbay,
48                 ATrack *track, int x, int y)
49  : PatchGUI(mwindow, patchbay, track, x, y)
50 {
51         data_type = TRACK_AUDIO;
52         this->atrack = track;
53         meter = 0;
54         pan = 0;
55         fade = 0;
56 }
57
58 APatchGUI::~APatchGUI()
59 {
60         if( fade ) delete fade;
61         if( meter ) delete meter;
62         if( pan ) delete pan;
63 }
64
65 void APatchGUI::create_objects()
66 {
67         update(x, y);
68 }
69
70 int APatchGUI::reposition(int x, int y)
71 {
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( meter )
78                 meter->reposition_window(meter->get_x(), y1+y, -1, meter->get_w());
79         y1 += mwindow->theme->meter_h;
80         if( mix )
81                 mix->reposition_window(mix->get_x(), y1+y);
82         if( pan )
83                 pan->reposition_window(pan->get_x(), y1+y);
84         if( nudge )
85                 nudge->reposition_window(nudge->get_x(), y1+y);
86         y1 += mwindow->theme->pan_h;
87
88         return y1;
89 }
90
91 int APatchGUI::update(int x, int y)
92 {
93         int h = track->vertical_span(mwindow->theme);
94         int x1 = 0;
95         int y1 = PatchGUI::update(x, y);
96
97         int y2 = y1 + mwindow->theme->fade_h;
98         if( fade ) {
99                 if( h < y2 ) {
100                         delete fade;
101                         fade = 0;
102                 }
103                 else {
104                         FloatAuto *previous = 0, *next = 0;
105                         double unit_position = mwindow->edl->local_session->get_selectionstart(1);
106                         unit_position = mwindow->edl->align_to_frame(unit_position, 0);
107                         int64_t unit_pos = atrack->to_units(unit_position, 0);
108                         FloatAutos *ptr = (FloatAutos*)atrack->automation->autos[AUTOMATION_FADE];
109                         float value = ptr->get_value(unit_pos, PLAY_FORWARD, previous, next);
110                         fade->update(fade->get_w(), value,
111                                      mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_AUDIO_FADE],
112                                      mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_AUDIO_FADE]);
113                 }
114         }
115         else if( h >= y2 ) {
116                 float v = mwindow->get_float_auto(this, AUTOMATION_FADE)->get_value();
117                 patchbay->add_subwindow(fade = new AFadePatch(this, x1+x, y1+y,
118                         patchbay->get_w() - xS(10), v));
119         }
120         y1 = y2;
121
122         y2 = y1 + mwindow->theme->meter_h;
123         if( meter ) {
124                 if( h < y2 ) {
125                         delete meter;  meter = 0;
126                 }
127         }
128         else if( h >= y2 ) {
129                 patchbay->add_subwindow(meter = new AMeterPatch(mwindow, this, x1+x, y1+y));
130         }
131         y1 = y2;
132
133         y2 = y1 + mwindow->theme->pan_h;
134         if( pan ) {
135                 if( h < y2 ) {
136                         delete mix;    mix = 0;
137                         delete pan;    pan = 0;
138                         delete nudge;  nudge = 0;
139                 }
140                 else {
141                         if( mwindow->session->selected_zwindow >= 0 ) {
142                                 int v = mwindow->mixer_track_active(track);
143                                 mix->update(v);
144                         }
145                         if( pan->get_total_values() != mwindow->edl->session->audio_channels ) {
146                                 pan->change_channels(mwindow->edl->session->audio_channels,
147                                         mwindow->edl->session->achannel_positions);
148                         }
149                         else {
150                                 int handle_x, handle_y;
151                                 PanAuto *previous = 0, *next = 0;
152                                 double unit_position = mwindow->edl->local_session->get_selectionstart(1);
153                                 unit_position = mwindow->edl->align_to_frame(unit_position, 0);
154                                 unit_position = atrack->to_units(unit_position, 0);
155                                 PanAutos *ptr = (PanAutos*)atrack->automation->autos[AUTOMATION_PAN];
156                                 ptr->get_handle(handle_x, handle_y, (long)unit_position,
157                                                 PLAY_FORWARD, previous, next);
158                                 pan->update(handle_x, handle_y);
159                         }
160                         nudge->update();
161                 }
162         }
163         else if( h >= y2 ) {
164                 patchbay->add_subwindow(mix = new AMixPatch(mwindow, this, x1+x, y1+y+5));
165                 x1 += mix->get_w() + xS(10);
166                 patchbay->add_subwindow(pan = new APanPatch(mwindow, this, x1+x, y1+y));
167                 x1 += pan->get_w() + xS(20);
168                 patchbay->add_subwindow(nudge = new NudgePatch(mwindow, this, x1+x, y1+y,
169                                 patchbay->get_w() - x1-x - xS(10)));
170         }
171         y1 = y2;
172
173         return y1;
174 }
175
176 void APatchGUI::update_faders(float v)
177 {
178         if( fade )
179                 fade->update(v);
180
181         change_source = 1;
182         double position = mwindow->edl->local_session->get_selectionstart(1);
183         Autos *fade_autos = atrack->automation->autos[AUTOMATION_FADE];
184         int need_undo = !fade_autos->auto_exists_for_editing(position);
185         mwindow->undo->update_undo_before(_("fade"), need_undo ? 0 : this);
186         FloatAuto *current = (FloatAuto*)fade_autos->get_auto_for_editing(position);
187         float change = v - current->get_value(edge);
188         current->bump_value(v, edge, span);
189         if( track->is_ganged() && track->is_armed() )
190                 patchbay->synchronize_faders(change, TRACK_AUDIO, track, edge, span);
191         mwindow->undo->update_undo_after(_("fade"), LOAD_AUTOMATION);
192         change_source = 0;
193
194         mwindow->sync_parameters(CHANGE_PARAMS);
195
196         if( mwindow->edl->session->auto_conf->autos[AUTOMATION_FADE] ) {
197                 mwindow->gui->draw_overlays(1);
198         }
199 }
200
201 AFadePatch::AFadePatch(APatchGUI *patch, int x, int y, int w, float v)
202  : BC_FSlider(x, y, 0, w, w,
203         patch->mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_AUDIO_FADE],
204         patch->mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_AUDIO_FADE],
205         v)
206 {
207         this->patch = patch;
208 }
209
210
211 int AFadePatch::handle_event()
212 {
213         if( shift_down() ) {
214                 update(0.0);
215                 set_tooltip(get_caption());
216         }
217         patch->update_faders(get_value());
218         return 1;
219 }
220
221 AKeyFadePatch::AKeyFadePatch(MWindow *mwindow, APatchGUI *gui,
222                         int bump, int x, int y)
223  : BC_SubWindow(x,y, xS(200)+4,yS(bump ? 50 : 24)+4,
224                 GWindowGUI::auto_colors[AUTOMATION_FADE])
225 {
226         this->mwindow = mwindow;
227         this->gui = gui;
228 }
229 AKeyFadePatch::~AKeyFadePatch()
230 {
231 }
232
233 void AKeyFadePatch::create_objects()
234 {
235         int x = 2, x1 = x, y = 0, dy = 0;
236         FloatAuto *fade_auto = mwindow->get_float_auto(gui, AUTOMATION_FADE);
237         float v = fade_auto->get_value(gui->edge);
238         add_subwindow(akey_fade_text = new AKeyFadeText(this, x, y, xS(64), v));
239         x += akey_fade_text->get_w();
240         dy = bmax(dy, akey_fade_text->get_h());
241         VFrame **lok_images = mwindow->theme->get_image_set("lok");
242         int w1 = get_w()-2 - x - lok_images[0]->get_w();
243         add_subwindow(akey_fade_slider = new AKeyFadeSlider(this, x, y, w1, v));
244         x += akey_fade_slider->get_w();
245         dy = bmax(dy, akey_fade_slider->get_h());
246         add_subwindow(akey_fade_ok = new AKeyFadeOK(this, x, y, lok_images));
247         dy = bmax(dy, akey_fade_ok->get_h());
248         if( fade_auto->is_bump() ) {
249                 y += dy;
250                 set_color(get_resources()->get_bg_color());
251                 draw_box(0,y, get_w(),get_h());
252                 add_subwindow(auto_edge = new AKeyPatchAutoEdge(mwindow, this, x1, y));
253                 x1 += auto_edge->get_w() + xS(15);
254                 add_subwindow(auto_span = new AKeyPatchAutoSpan(mwindow, this, x1, y));
255         }
256         draw_3d_border(0,0, get_w(), get_h(), 0);
257         activate();
258         show_window();
259 }
260
261 void AKeyFadePatch::set_edge(int edge)
262 {
263         gui->edge = edge;
264         FloatAuto *fade_auto = mwindow->get_float_auto(gui, AUTOMATION_FADE);
265         float v = fade_auto->get_value(edge);
266         update(v);
267 }
268
269 void AKeyFadePatch::set_span(int span)
270 {
271         gui->span = span;
272 }
273
274 void AKeyFadePatch::update(float v)
275 {
276         akey_fade_text->update(v);
277         akey_fade_slider->update(v);
278         gui->update_faders(v);
279 }
280
281 AKeyFadeOK::AKeyFadeOK(AKeyFadePatch *akey_fade_patch, int x, int y, VFrame **images)
282  : BC_Button(x, y, images)
283 {
284         this->akey_fade_patch = akey_fade_patch;
285 }
286
287 int AKeyFadeOK::handle_event()
288 {
289         MWindow *mwindow = akey_fade_patch->mwindow;
290         mwindow->gui->close_keyvalue_popup();
291         return 1;
292 }
293
294 AKeyFadeText::AKeyFadeText(AKeyFadePatch *akey_fade_patch, int x, int y, int w, float v)
295  : BC_TextBox(x, y, w, 1, v, 1, MEDIUMFONT, 2)
296 {
297         this->akey_fade_patch = akey_fade_patch;
298 }
299
300 int AKeyFadeText::handle_event()
301 {
302         float v = atof(get_text());
303         akey_fade_patch->update(v);
304         return get_keypress() != RETURN ? 1 :
305                 akey_fade_patch->akey_fade_ok->handle_event();
306 }
307
308 AKeyFadeSlider::AKeyFadeSlider(AKeyFadePatch *akey_fade_patch, int x, int y, int w, float v)
309  : AFadePatch(akey_fade_patch->gui, x, y, w, v)
310 {
311         this->akey_fade_patch = akey_fade_patch;
312 }
313
314 int AKeyFadeSlider::handle_event()
315 {
316         float v = get_value();
317         akey_fade_patch->update(v);
318         return 1;
319 }
320
321
322 APanPatch::APanPatch(MWindow *mwindow, APatchGUI *patch, int x, int y)
323  : BC_Pan(x, y, PAN_RADIUS, MAX_PAN,
324         mwindow->edl->session->audio_channels,
325         mwindow->edl->session->achannel_positions,
326         mwindow->get_pan_auto(patch)->handle_x,
327         mwindow->get_pan_auto(patch)->handle_y,
328         mwindow->get_pan_auto(patch)->values)
329 {
330         this->mwindow = mwindow;
331         this->patch = patch;
332         set_tooltip(_("Pan"));
333 }
334
335 int APanPatch::handle_event()
336 {
337         PanAuto *current;
338         double position = mwindow->edl->local_session->get_selectionstart(1);
339         Autos *pan_autos = patch->atrack->automation->autos[AUTOMATION_PAN];
340         int need_undo = !pan_autos->auto_exists_for_editing(position);
341         mwindow->undo->update_undo_before(_("pan"), need_undo ? 0 : this);
342         current = (PanAuto*)pan_autos->get_auto_for_editing(position);
343         current->handle_x = get_stick_x();
344         current->handle_y = get_stick_y();
345         memcpy(current->values, get_values(), sizeof(float) * mwindow->edl->session->audio_channels);
346         mwindow->undo->update_undo_after(_("pan"), LOAD_AUTOMATION);
347         mwindow->sync_parameters(CHANGE_PARAMS);
348         if( need_undo && mwindow->edl->session->auto_conf->autos[AUTOMATION_PAN] ) {
349                 mwindow->gui->draw_overlays(1);
350         }
351         return 1;
352 }
353
354 AKeyPanPatch::AKeyPanPatch(MWindow *mwindow, APatchGUI *patch)
355  : APanPatch(mwindow, patch, -1,-1)
356 {
357 }
358
359 int AKeyPanPatch::handle_event()
360 {
361         int ret = APanPatch::handle_event();
362         APanPatch *pan = patch->pan;
363         if( pan )
364                 pan->update(get_stick_x(), get_stick_y());
365         return ret;
366 }
367
368
369 AMeterPatch::AMeterPatch(MWindow *mwindow, APatchGUI *patch, int x, int y)
370  : BC_Meter(x, y, METER_HORIZ, patch->patchbay->get_w() - xS(10),
371         mwindow->edl->session->min_meter_db, mwindow->edl->session->max_meter_db,
372         mwindow->edl->session->meter_format, 0, -1)
373 {
374         this->mwindow = mwindow;
375         this->patch = patch;
376         set_delays(TRACKING_RATE * 10, TRACKING_RATE);
377 }
378
379 int AMeterPatch::button_press_event()
380 {
381         if( cursor_inside() && is_event_win() && get_buttonpress() == 1 ) {
382                 mwindow->reset_meters();
383                 return 1;
384         }
385
386         return 0;
387 }
388
389 AMixPatch::AMixPatch(MWindow *mwindow, APatchGUI *patch, int x, int y)
390  : MixPatch(mwindow, patch, x, y)
391 {
392         set_tooltip(_("Mixer"));
393 }
394
395 AMixPatch::~AMixPatch()
396 {
397 }
398
399 AKeyPatchAutoEdge::AKeyPatchAutoEdge(MWindow *mwindow,
400                 AKeyFadePatch *patch, int x, int y)
401  : BC_Toggle(x, y, mwindow->theme->get_image_set("bump_edge"),
402                 patch->gui->edge,_("Edge"))
403 {
404         this->mwindow = mwindow;
405         this->patch = patch;
406         set_tooltip(_("Bump uses left edge"));
407 }
408
409 int AKeyPatchAutoEdge::handle_event()
410 {
411         patch->set_edge(get_value());
412         return 1;
413 }
414
415 AKeyPatchAutoSpan::AKeyPatchAutoSpan(MWindow *mwindow,
416                 AKeyFadePatch *patch, int x, int y)
417  :  BC_Toggle(x, y, mwindow->theme->get_image_set("bump_span"),
418                 patch->gui->span,_("Span"))
419 {
420         this->mwindow = mwindow;
421         this->patch = patch;
422         set_tooltip(_("Bump spans to next"));
423 }
424
425 int AKeyPatchAutoSpan::handle_event()
426 {
427         patch->set_span(get_value());
428         return 1;
429 }
430