Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / 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::is_stopped()
133 {
134         return engine->command->command == STOP ? 1 : 0;
135 }
136
137 int PlayTransport::flip_vertical(int vertical, int &x, int &y)
138 {
139         if(vertical)
140         {
141                 rewind_button->reposition_window(x, y);
142                 y += rewind_button->get_h();
143                 fast_reverse->reposition_window(x, y);
144                 y += fast_reverse->get_h();
145                 reverse_play->reposition_window(x, y);
146                 y += reverse_play->get_h();
147                 frame_reverse_play->reposition_window(x, y);
148                 y += frame_reverse_play->get_h();
149                 stop_button->reposition_window(x, y);
150                 y += stop_button->get_h();
151                 frame_forward_play->reposition_window(x, y);
152                 y += frame_forward_play->get_h();
153                 forward_play->reposition_window(x, y);
154                 y += forward_play->get_h();
155                 fast_play->reposition_window(x, y);
156                 y += fast_play->get_h();
157                 end_button->reposition_window(x, y);
158                 y += end_button->get_h();
159         }
160         else
161         {
162                 rewind_button->reposition_window(x, y - 2);
163                 x += rewind_button->get_w();
164                 fast_reverse->reposition_window(x, y - 2);
165                 x += fast_reverse->get_w();
166                 reverse_play->reposition_window(x, y - 2);
167                 x += reverse_play->get_w();
168                 frame_reverse_play->reposition_window(x, y - 2);
169                 x += frame_reverse_play->get_w();
170                 stop_button->reposition_window(x, y - 2);
171                 x += stop_button->get_w();
172                 frame_forward_play->reposition_window(x, y - 2);
173                 x += frame_forward_play->get_w();
174                 forward_play->reposition_window(x, y - 2);
175                 x += forward_play->get_w();
176                 fast_play->reposition_window(x, y - 2);
177                 x += fast_play->get_w();
178                 end_button->reposition_window(x, y - 2);
179                 x += end_button->get_w();
180         }
181
182         return 0;
183 }
184
185 int PlayTransport::keypress_event()
186 {
187         int key = subwindow->get_keypress();
188         return do_keypress(key);
189 }
190
191 int PlayTransport::do_keypress(int key)
192 {
193         int result = 1;
194 // unqualified keys, still holding lock
195         switch( key ) {
196         case HOME:
197                 goto_start();
198                 return result;
199         case END:
200                 goto_end();
201                 return result;
202         }
203 // as in play_command
204         int ctrl_key = subwindow->ctrl_down() ? 1 : 0;
205         int shft_key = subwindow->shift_down() ? 1 : 0;
206         int alt_key = subwindow->alt_down() ? 1 : 0;
207         int use_inout = ctrl_key;
208         int toggle_audio = shft_key & ~ctrl_key;
209         int loop_play = shft_key & ctrl_key;
210         int command = -1, prev_command = engine->command->command;
211         using_inout = use_inout;
212         subwindow->unlock_window();
213
214         result = 0;
215         switch( key ) {
216         case KPINS:     command = STOP;                 break;
217         case KPPLUS:    command = FAST_REWIND;          break;
218         case KP6:       command = NORMAL_REWIND;        break;
219         case KP5:       command = SLOW_REWIND;          break;
220         case KP4:       command = SINGLE_FRAME_REWIND;  break;
221         case KP1:       command = SINGLE_FRAME_FWD;     break;
222         case KP2:       command = SLOW_FWD;             break;
223         case KP3:       command = NORMAL_FWD;           break;
224         case KPENTER:   command = FAST_FWD;             break;
225         case ' ':
226                 switch( prev_command ) {
227                 case COMMAND_NONE:
228                 case CURRENT_FRAME:
229                 case LAST_FRAME:
230                 case PAUSE:
231                 case STOP:
232                         command = NORMAL_FWD;
233                         break;
234                 default:
235                         command = STOP;
236                         break;
237                 }
238                 break;
239         case 'u': case 'U':
240                 if( alt_key ) command = SINGLE_FRAME_REWIND;
241                 break;
242         case 'i': case 'I':
243                 if( alt_key ) command = SLOW_REWIND;
244                 break;
245         case 'o': case 'O':
246                 if( alt_key ) command = NORMAL_REWIND;
247                 break;
248         case 'p': case 'P':
249                 if( alt_key ) command = FAST_REWIND;
250                 break;
251         case 'j': case 'J':
252                 if( alt_key ) command = SINGLE_FRAME_FWD;
253                 break;
254         case 'k': case 'K':
255                 if( alt_key ) command = SLOW_FWD;
256                 break;
257         case 'l': case 'L':
258                 if( alt_key ) command = NORMAL_FWD;
259                 break;
260         case ':': case ';':
261                 if( alt_key ) command = FAST_FWD;
262                 break;
263         case 'm': case 'M':
264                 if( alt_key ) command = STOP;
265                 break;
266         }
267         if( command >= 0 ) {
268                 handle_transport(command, 0, use_inout, 1, toggle_audio, loop_play);
269                 result = 1;
270         }
271
272         subwindow->lock_window("PlayTransport::keypress_event 5");
273         return result;
274 }
275
276
277 void PlayTransport::goto_start()
278 {
279         handle_transport(REWIND, 1, 0);
280 }
281
282 void PlayTransport::goto_end()
283 {
284         handle_transport(GOTO_END, 1, 0);
285 }
286
287
288
289 void PlayTransport::handle_transport(int command, int wait_tracking, int use_inout,
290                 int update_refresh, int toggle_audio, int loop_play)
291 {
292         EDL *edl = get_edl();
293         if( !edl ) return;
294         if( !is_vwindow() )
295                 mwindow->queue_mixers(edl, command, wait_tracking, use_inout, update_refresh, toggle_audio, 0);
296         engine->issue_command(edl, command, wait_tracking, use_inout, update_refresh, toggle_audio, loop_play);
297 }
298
299 EDL* PlayTransport::get_edl()
300 {
301         return mwindow->edl;
302 }
303
304 int PlayTransport::pause_transport()
305 {
306         if(active_button) active_button->set_mode(PLAY_MODE);
307         return 0;
308 }
309
310
311 int PlayTransport::reset_transport()
312 {
313         fast_reverse->set_mode(PLAY_MODE);
314         reverse_play->set_mode(PLAY_MODE);
315         forward_play->set_mode(PLAY_MODE);
316         frame_reverse_play->set_mode(PLAY_MODE);
317         frame_forward_play->set_mode(PLAY_MODE);
318         fast_play->set_mode(PLAY_MODE);
319         return 0;
320 }
321
322 PTransportButton::PTransportButton(MWindow *mwindow, PlayTransport *transport, int x, int y, VFrame **data)
323  : BC_Button(x, y, data)
324 {
325         this->mwindow = mwindow;
326         this->transport = transport;
327         mode = PLAY_MODE;
328 }
329 PTransportButton::~PTransportButton()
330 {
331 }
332
333 int PTransportButton::set_mode(int mode)
334 {
335         this->mode = mode;
336         return 0;
337 }
338
339 int PTransportButton::play_command(const char *lock_msg, int command)
340 {
341         int ctrl_key = transport->subwindow->ctrl_down() ? 1 : 0;
342         int shft_key = transport->subwindow->shift_down() ? 1 : 0;
343         int use_inout = ctrl_key;
344         int toggle_audio = shft_key & ~ctrl_key;
345         int loop_play = shft_key & ctrl_key;
346         unlock_window();
347         transport->handle_transport(command, 0, use_inout, 0, toggle_audio, loop_play);
348         lock_window(lock_msg);
349         return 1;
350 }
351
352
353 RewindButton::RewindButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
354  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("rewind"))
355 {
356         set_tooltip(_("Rewind ( Home )"));
357 }
358 int RewindButton::handle_event()
359 {
360 //      unlock_window();
361         transport->goto_start();
362 //      lock_window();
363         return 1;
364 }
365
366 FastReverseButton::FastReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
367  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastrev"))
368 {
369         set_tooltip(_("Fast reverse ( + or Alt-p )"));
370 }
371 int FastReverseButton::handle_event()
372 {
373         return play_command("FastReverseButton::handle_event", FAST_REWIND);
374 }
375
376 // Reverse playback normal speed
377
378 ReverseButton::ReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
379  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("reverse"))
380 {
381         set_tooltip(_("Normal reverse ( 6 or Alt-o )"));
382 }
383 int ReverseButton::handle_event()
384 {
385         return play_command("ReverseButton::handle_event", NORMAL_REWIND);
386 }
387
388 // Reverse playback one frame
389
390 FrameReverseButton::FrameReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
391  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framerev"))
392 {
393         set_tooltip(_("Frame reverse ( 4 or Alt-u )"));
394 }
395 int FrameReverseButton::handle_event()
396 {
397         unlock_window();
398         transport->handle_transport(SINGLE_FRAME_REWIND, 0, ctrl_down());
399         lock_window("FrameReverseButton::handle_event");
400         return 1;
401 }
402
403 // forward playback normal speed
404
405 PlayButton::PlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
406  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("play"))
407 {
408         set_tooltip(_("Normal forward ( 3 or Alt-l )"));
409 }
410 int PlayButton::handle_event()
411 {
412         return play_command("PlayButton::handle_event", NORMAL_FWD);
413 }
414
415
416
417 // forward playback one frame
418
419 FramePlayButton::FramePlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
420  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framefwd"))
421 {
422         set_tooltip(_("Frame forward ( 1 or Alt-j )"));
423 }
424 int FramePlayButton::handle_event()
425 {
426         unlock_window();
427         transport->handle_transport(SINGLE_FRAME_FWD, 0, ctrl_down());
428         lock_window("FramePlayButton::handle_event");
429         return 1;
430 }
431
432
433
434 FastPlayButton::FastPlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
435  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastfwd"))
436 {
437         set_tooltip(_("Fast forward ( Enter or Alt-; )"));
438 }
439 int FastPlayButton::handle_event()
440 {
441         return play_command("FastPlayButton::handle_event", FAST_FWD);
442 }
443
444 EndButton::EndButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
445  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("end"))
446 {
447         set_tooltip(_("Jump to end ( End )"));
448 }
449 int EndButton::handle_event()
450 {
451 //      unlock_window();
452         transport->goto_end();
453 //      lock_window();
454         return 1;
455 }
456
457 StopButton::StopButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
458  : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("stop"))
459 {
460         set_tooltip(_("Stop ( 0 or Alt-m )"));
461 }
462 int StopButton::handle_event()
463 {
464         unlock_window();
465         transport->handle_transport(STOP, 0, 0);
466         lock_window("StopButton::handle_event");
467         return 1;
468 }
469
470
471
472 void PlayTransport::change_position(double position)
473 {
474         if( !get_edl() ) return;
475         int prev_command = engine->command->command;
476 // stop transport
477         if( prev_command != STOP && prev_command != COMMAND_NONE &&
478             prev_command != SINGLE_FRAME_FWD && prev_command != SINGLE_FRAME_REWIND ) {
479                 engine->que->send_command(STOP, CHANGE_NONE, 0, 0);
480                 engine->interrupt_playback(0);
481         }
482         mwindow->gui->lock_window("PlayTransport::change_position");
483         mwindow->goto_position(position);
484         mwindow->gui->unlock_window();
485 // restart command
486         switch(prev_command) {
487         case FAST_REWIND:
488         case NORMAL_REWIND:
489         case SLOW_REWIND:
490         case SLOW_FWD:
491         case NORMAL_FWD:
492         case FAST_FWD:
493                 engine->que->send_command(prev_command, CHANGE_NONE,
494                                 get_edl(), 1, 1, using_inout, 0);
495         }
496 }
497