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