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