RafaMar + programmer friend Help button in Batch Render addition
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / playtransport.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 "edl.h"
23 #include "keys.h"
24 #include "language.h"
25 #include "localsession.h"
26 #include "mwindow.h"
27 #include "mwindowgui.h"
28 #include "playbackengine.h"
29 #include "playtransport.h"
30 #include "preferences.h"
31 #include "shuttle.h"
32 #include "theme.h"
33 #include "tracks.h"
34 #include "transportque.h"
35 #include "vframe.h"
36
37
38
39 PlayTransport::PlayTransport(MWindow *mwindow,
40         BC_WindowBase *subwindow,
41         int x,
42         int y)
43 {
44         this->subwindow = subwindow;
45         this->mwindow = mwindow;
46         this->x = x;
47         this->y = y;
48         this->engine = 0;
49         this->status = 0;
50         this->using_inout = 0;
51 }
52
53
54 PlayTransport::~PlayTransport()
55 {
56         delete forward_play;
57         delete frame_forward_play;
58         delete reverse_play;
59         delete frame_reverse_play;
60         delete fast_reverse;
61         delete fast_play;
62         delete rewind_button;
63         delete stop_button;
64         delete end_button;
65 }
66
67 void PlayTransport::set_engine(PlaybackEngine *engine)
68 {
69         this->engine = engine;
70 }
71
72 int PlayTransport::get_transport_width(MWindow *mwindow)
73 {
74         return mwindow->theme->get_image_set("stop")[0]->get_w() * 7 +
75                 mwindow->theme->get_image_set("rewind")[0]->get_w() * 2;
76 }
77
78 void PlayTransport::create_objects()
79 {
80         int x = this->x, y = this->y;
81         subwindow->add_subwindow(rewind_button = new RewindButton(mwindow, this, x, y));
82         x += rewind_button->get_w();
83         subwindow->add_subwindow(fast_reverse = new FastReverseButton(mwindow, this, x, y));
84         x += fast_reverse->get_w();
85         subwindow->add_subwindow(reverse_play = new ReverseButton(mwindow, this, x, y));
86         x += reverse_play->get_w();
87         subwindow->add_subwindow(frame_reverse_play = new FrameReverseButton(mwindow, this, x, y));
88         x += frame_reverse_play->get_w();
89         subwindow->add_subwindow(stop_button = new StopButton(mwindow, this, x, y));
90         x += stop_button->get_w();
91         subwindow->add_subwindow(frame_forward_play = new FramePlayButton(mwindow, this, x, y));
92         x += frame_forward_play->get_w();
93         subwindow->add_subwindow(forward_play = new PlayButton(mwindow, this, x, y));
94         x += forward_play->get_w();
95         subwindow->add_subwindow(fast_play = new FastPlayButton(mwindow, this, x, y));
96         x += fast_play->get_w();
97         subwindow->add_subwindow(end_button = new EndButton(mwindow, this, x, y));
98         x += end_button->get_w();
99
100         reverse = 0;
101         speed = 0;
102
103 }
104
105 void PlayTransport::reposition_buttons(int x, int y)
106 {
107         this->x = x;
108         this->y = y;
109         rewind_button->reposition_window(x, y);
110         x += rewind_button->get_w();
111         fast_reverse->reposition_window(x, y);
112         x += fast_reverse->get_w();
113         reverse_play->reposition_window(x, y);
114         x += reverse_play->get_w();
115         frame_reverse_play->reposition_window(x, y);
116         x += frame_reverse_play->get_w();
117         stop_button->reposition_window(x, y);
118         x += stop_button->get_w();
119         frame_forward_play->reposition_window(x, y);
120         x += frame_forward_play->get_w();
121         forward_play->reposition_window(x, y);
122         x += forward_play->get_w();
123         fast_play->reposition_window(x, y);
124         x += fast_play->get_w();
125         end_button->reposition_window(x, y);
126         x += end_button->get_w();
127 }
128
129 int PlayTransport::get_w()
130 {
131         return end_button->get_x() + end_button->get_w() - rewind_button->get_x();
132 }
133
134 int PlayTransport::is_stopped()
135 {
136         return engine->is_playing_back ? 0 : 1;
137 }
138
139 int PlayTransport::flip_vertical(int vertical, int &x, int &y)
140 {
141         if(vertical)
142         {
143                 rewind_button->reposition_window(x, y);
144                 y += rewind_button->get_h();
145                 fast_reverse->reposition_window(x, y);
146                 y += fast_reverse->get_h();
147                 reverse_play->reposition_window(x, y);
148                 y += reverse_play->get_h();
149                 frame_reverse_play->reposition_window(x, y);
150                 y += frame_reverse_play->get_h();
151                 stop_button->reposition_window(x, y);
152                 y += stop_button->get_h();
153                 frame_forward_play->reposition_window(x, y);
154                 y += frame_forward_play->get_h();
155                 forward_play->reposition_window(x, y);
156                 y += forward_play->get_h();
157                 fast_play->reposition_window(x, y);
158                 y += fast_play->get_h();
159                 end_button->reposition_window(x, y);
160                 y += end_button->get_h();
161         }
162         else
163         {
164                 rewind_button->reposition_window(x, y - 2);
165                 x += rewind_button->get_w();
166                 fast_reverse->reposition_window(x, y - 2);
167                 x += fast_reverse->get_w();
168                 reverse_play->reposition_window(x, y - 2);
169                 x += reverse_play->get_w();
170                 frame_reverse_play->reposition_window(x, y - 2);
171                 x += frame_reverse_play->get_w();
172                 stop_button->reposition_window(x, y - 2);
173                 x += stop_button->get_w();
174                 frame_forward_play->reposition_window(x, y - 2);
175                 x += frame_forward_play->get_w();
176                 forward_play->reposition_window(x, y - 2);
177                 x += forward_play->get_w();
178                 fast_play->reposition_window(x, y - 2);
179                 x += fast_play->get_w();
180                 end_button->reposition_window(x, y - 2);
181                 x += end_button->get_w();
182         }
183
184         return 0;
185 }
186
187 int PlayTransport::keypress_event()
188 {
189         int key = subwindow->get_keypress();
190         return do_keypress(key);
191 }
192
193 int PlayTransport::do_keypress(int key)
194 {
195         int result = 1;
196 // unqualified keys, still holding lock
197         switch( key ) {
198         case HOME:
199                 goto_start();
200                 return result;
201         case END:
202                 goto_end();
203                 return result;
204         }
205
206         int ctrl_key = subwindow->ctrl_down() ? 1 : 0;
207         int shft_key = subwindow->shift_down() ? 1 : 0;
208         int alt_key = subwindow->alt_down() ? 1 : 0;
209         int use_inout = ctrl_key;
210         int toggle_audio = shft_key & ~ctrl_key;
211         int loop_play = shft_key & ctrl_key;
212         float speed = 0;
213         int command = -1;
214         int curr_command = engine->is_playing_back ? engine->command->command : STOP;
215         subwindow->unlock_window();
216
217         result = 0;
218
219         if( key >= SKEY_MIN && key <= SKEY_MAX ) {
220                 speed = SHUTTLE_MAX_SPEED *
221                          (key - (SKEY_MAX + SKEY_MIN)/2.f) /
222                                 ((SKEY_MAX - SKEY_MIN) / 2.f);
223                 if( speed < 0 ) {
224                         speed = -speed;
225                         command = speed < 1 ? SLOW_REWIND :
226                                 speed > 1 ? FAST_REWIND : NORMAL_REWIND;
227                 }
228                 else if( speed > 0 ) {
229                         command = speed < 1 ? SLOW_FWD :
230                                 speed > 1 ? FAST_FWD : NORMAL_FWD;
231                 }
232                 else
233                         command = STOP;
234                 use_inout = 0;
235                 loop_play = 0;
236         }
237         else switch( key ) {
238         case KPINS:     command = STOP;                 break;
239         case KPPLUS:    command = FAST_REWIND;          break;
240         case KP6:       command = NORMAL_REWIND;        break;
241         case KP5:       command = SLOW_REWIND;          break;
242         case KP4:       command = SINGLE_FRAME_REWIND;  break;
243         case KP1:       command = SINGLE_FRAME_FWD;     break;
244         case KP2:       command = SLOW_FWD;             break;
245         case KP3:       command = NORMAL_FWD;           break;
246         case KPENTER:   command = FAST_FWD;             break;
247
248         case ' ':
249                 switch( curr_command ) {
250                 case COMMAND_NONE:
251                 case CURRENT_FRAME:
252                 case LAST_FRAME:
253                 case PAUSE:
254                 case STOP:
255                         command = NORMAL_FWD;
256                         break;
257                 default:
258                         command = STOP;
259                         break;
260                 }
261                 break;
262         case 'u': case 'U':
263                 if( alt_key ) command = SINGLE_FRAME_REWIND;
264                 break;
265         case 'i': case 'I':
266                 if( alt_key ) command = SLOW_REWIND;
267                 break;
268         case 'o': case 'O':
269                 if( alt_key ) command = NORMAL_REWIND;
270                 break;
271         case 'p': case 'P':
272                 if( alt_key ) command = FAST_REWIND;
273                 break;
274         case 'j': case 'J':
275                 if( alt_key ) command = SINGLE_FRAME_FWD;
276                 break;
277         case 'k': case 'K':
278                 if( alt_key ) command = SLOW_FWD;
279                 break;
280         case 'l': case 'L':
281                 if( alt_key ) command = NORMAL_FWD;
282                 break;
283         case ':': case ';':
284                 if( alt_key ) command = FAST_FWD;
285                 break;
286         case 'm': case 'M':
287                 if( alt_key ) command = STOP;
288                 break;
289         }
290         if( command >= 0 ) {
291                 handle_transport(command, 0, use_inout, toggle_audio, loop_play, speed);
292                 result = 1;
293         }
294
295         subwindow->lock_window("PlayTransport::keypress_event 5");
296         return result;
297 }
298
299
300 void PlayTransport::goto_start()
301 {
302         handle_transport(REWIND, 1);
303 }
304
305 void PlayTransport::goto_end()
306 {
307         handle_transport(GOTO_END, 1);
308 }
309
310
311
312 void PlayTransport::handle_transport(int command, int wait_tracking,
313                 int use_inout, int toggle_audio, int loop_play, float speed)
314 {
315         EDL *edl = get_edl();
316         if( !edl ) return;
317         using_inout = use_inout;
318
319         if( use_mixers() )
320                 mwindow->handle_mixers(edl, command, wait_tracking,
321                                 use_inout, toggle_audio, 0, speed);
322         engine->next_command->toggle_audio = toggle_audio;
323         engine->next_command->loop_play = loop_play;
324         engine->next_command->speed = speed;
325         engine->send_command(command, edl, wait_tracking, use_inout);
326 }
327
328 EDL* PlayTransport::get_edl()
329 {
330         return mwindow->edl;
331 }
332
333 int PlayTransport::set_transport(int mode)
334 {
335         fast_reverse->set_mode(mode);
336         reverse_play->set_mode(mode);
337         forward_play->set_mode(mode);
338         frame_reverse_play->set_mode(mode);
339         frame_forward_play->set_mode(mode);
340         fast_play->set_mode(mode);
341         return 0;
342 }
343
344 PTransportButton::PTransportButton(MWindow *mwindow, PlayTransport *transport, int x, int y, VFrame **data)
345  : BC_Button(x, y, data)
346 {
347         this->mwindow = mwindow;
348         this->transport = transport;
349         mode = PLAY_MODE;
350 }
351 PTransportButton::~PTransportButton()
352 {
353 }
354
355 void PTransportButton::set_mode(int mode)
356 {
357         this->mode = mode;
358 }
359
360 void PTransportButton::loop_mode(int dir)
361 {
362         if( mode != LOOP_MODE ) return;
363         EDL *edl = transport->get_edl();
364         if( !edl ) return;
365         PlaybackEngine *engine = transport->engine;
366         if( !engine || engine->is_playing_back ) return;
367         double position = engine->get_tracking_position();
368         switch( dir ) {
369         case PLAY_FORWARD:
370                 if( position >= edl->tracks->total_playable_length() )
371                         transport->goto_start();
372                 break;
373         case PLAY_REVERSE:
374                 if( position <= 0 )
375                         transport->goto_end();
376                 break;
377         }
378 }
379
380 int PTransportButton::play_command(const char *lock_msg, int command)
381 {
382         int ctrl_key = transport->subwindow->ctrl_down() ? 1 : 0;
383         int shft_key = transport->subwindow->shift_down() ? 1 : 0;
384         int use_inout = ctrl_key;
385         int toggle_audio = shft_key & ~ctrl_key;
386         int loop_play = shft_key & ctrl_key;
387         unlock_window();
388         transport->handle_transport(command, 0, use_inout, toggle_audio, loop_play, 0);
389         lock_window(lock_msg);
390         return 1;
391 }
392
393
394 RewindButton::RewindButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
395  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("rewind"))
396 {
397         set_tooltip(_("Rewind ( Home )"));
398 }
399 int RewindButton::handle_event()
400 {
401 //      unlock_window();
402         transport->goto_start();
403 //      lock_window();
404         return 1;
405 }
406
407 FastReverseButton::FastReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
408  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastrev"))
409 {
410         set_tooltip(_("Fast reverse ( + or Alt-p )"));
411 }
412 int FastReverseButton::handle_event()
413 {
414         loop_mode(PLAY_REVERSE);
415         return play_command("FastReverseButton::handle_event", FAST_REWIND);
416 }
417
418 // Reverse playback normal speed
419
420 ReverseButton::ReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
421  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("reverse"))
422 {
423         set_tooltip(_("Normal reverse ( 6 or Alt-o )"));
424 }
425 int ReverseButton::handle_event()
426 {
427         loop_mode(PLAY_REVERSE);
428         return play_command("ReverseButton::handle_event", NORMAL_REWIND);
429 }
430
431 // Reverse playback one frame
432
433 FrameReverseButton::FrameReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
434  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framerev"))
435 {
436         set_tooltip(_("Frame reverse ( 4 or Alt-u )"));
437 }
438 int FrameReverseButton::handle_event()
439 {
440         unlock_window();
441         transport->handle_transport(SINGLE_FRAME_REWIND, 0, ctrl_down());
442         lock_window("FrameReverseButton::handle_event");
443         return 1;
444 }
445
446 // forward playback normal speed
447
448 PlayButton::PlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
449  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("play"))
450 {
451         set_tooltip(_("Normal forward ( 3 or Alt-l )"));
452 }
453 int PlayButton::handle_event()
454 {
455         loop_mode(PLAY_FORWARD);
456         return play_command("PlayButton::handle_event", NORMAL_FWD);
457 }
458
459
460
461 // forward playback one frame
462
463 FramePlayButton::FramePlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
464  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framefwd"))
465 {
466         set_tooltip(_("Frame forward ( 1 or Alt-j )"));
467 }
468 int FramePlayButton::handle_event()
469 {
470         unlock_window();
471         transport->handle_transport(SINGLE_FRAME_FWD, 0, ctrl_down());
472         lock_window("FramePlayButton::handle_event");
473         return 1;
474 }
475
476
477
478 FastPlayButton::FastPlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
479  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastfwd"))
480 {
481         set_tooltip(_("Fast forward ( Enter or Alt-; )"));
482 }
483 int FastPlayButton::handle_event()
484 {
485         loop_mode(PLAY_FORWARD);
486         return play_command("FastPlayButton::handle_event", FAST_FWD);
487 }
488
489 EndButton::EndButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
490  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("end"))
491 {
492         set_tooltip(_("Jump to end ( End )"));
493 }
494 int EndButton::handle_event()
495 {
496 //      unlock_window();
497         transport->goto_end();
498 //      lock_window();
499         return 1;
500 }
501
502 StopButton::StopButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
503  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("stop"))
504 {
505         set_tooltip(_("Stop ( 0 or Alt-m )"));
506 }
507 int StopButton::handle_event()
508 {
509         unlock_window();
510         transport->handle_transport(STOP);
511         lock_window("StopButton::handle_event");
512         return 1;
513 }
514
515
516
517 void PlayTransport::change_position(double position)
518 {
519         if( !get_edl() ) return;
520         int command = engine->command->command;
521 // stop transport
522         engine->stop_playback(0);
523         mwindow->gui->lock_window("PlayTransport::change_position");
524         mwindow->goto_position(position);
525         mwindow->gui->unlock_window();
526 // restart command
527         switch( command ) {
528         case FAST_REWIND:
529         case NORMAL_REWIND:
530         case SLOW_REWIND:
531         case SLOW_FWD:
532         case NORMAL_FWD:
533         case FAST_FWD:
534                 engine->next_command->realtime = 1;
535                 engine->next_command->resume = 1;
536                 engine->transport_command(command, CHANGE_NONE, get_edl(), using_inout);
537         }
538 }
539