Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / playtransport.C
diff --git a/cinelerra-5.1/cinelerra/playtransport.C b/cinelerra-5.1/cinelerra/playtransport.C
new file mode 100644 (file)
index 0000000..b330c4d
--- /dev/null
@@ -0,0 +1,575 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "edl.h"
+#include "keys.h"
+#include "language.h"
+#include "localsession.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "playbackengine.h"
+#include "playtransport.h"
+#include "preferences.h"
+#include "theme.h"
+#include "transportque.h"
+#include "vframe.h"
+
+
+
+PlayTransport::PlayTransport(MWindow *mwindow, 
+       BC_WindowBase *subwindow, 
+       int x, 
+       int y)
+{
+       this->subwindow = subwindow;
+       this->mwindow = mwindow;
+       this->x = x;
+       this->y = y;
+       this->engine = 0;
+       this->status = 0;
+       this->using_inout = 0;
+}
+
+
+PlayTransport::~PlayTransport()
+{
+       delete forward_play;
+       delete frame_forward_play;
+       delete reverse_play;
+       delete frame_reverse_play;
+       delete fast_reverse;
+       delete fast_play;
+       delete rewind_button;
+       delete stop_button;
+       delete end_button;
+}
+
+void PlayTransport::set_engine(PlaybackEngine *engine)
+{
+       this->engine = engine;
+}
+
+int PlayTransport::get_transport_width(MWindow *mwindow)
+{
+       return mwindow->theme->get_image_set("stop")[0]->get_w() * 7 +
+               mwindow->theme->get_image_set("rewind")[0]->get_w() * 2;
+}
+
+void PlayTransport::create_objects()
+{
+       int x = this->x, y = this->y;
+       subwindow->add_subwindow(rewind_button = new RewindButton(mwindow, this, x, y));
+       x += rewind_button->get_w();
+       subwindow->add_subwindow(fast_reverse = new FastReverseButton(mwindow, this, x, y)); 
+       x += fast_reverse->get_w();
+       subwindow->add_subwindow(reverse_play = new ReverseButton(mwindow, this, x, y)); 
+       x += reverse_play->get_w();
+       subwindow->add_subwindow(frame_reverse_play = new FrameReverseButton(mwindow, this, x, y)); 
+       x += frame_reverse_play->get_w();
+       subwindow->add_subwindow(stop_button = new StopButton(mwindow, this, x, y)); 
+       x += stop_button->get_w();
+       subwindow->add_subwindow(frame_forward_play = new FramePlayButton(mwindow, this, x, y)); 
+       x += frame_forward_play->get_w();
+       subwindow->add_subwindow(forward_play = new PlayButton(mwindow, this, x, y)); 
+       x += forward_play->get_w();
+       subwindow->add_subwindow(fast_play = new FastPlayButton(mwindow, this, x, y)); 
+       x += fast_play->get_w();
+       subwindow->add_subwindow(end_button = new EndButton(mwindow, this, x, y)); 
+       x += end_button->get_w();
+
+       reverse = 0;
+       speed = 0;
+
+}
+
+void PlayTransport::reposition_buttons(int x, int y)
+{
+       this->x = x;
+       this->y = y;
+       rewind_button->reposition_window(x, y);
+       x += rewind_button->get_w();
+       fast_reverse->reposition_window(x, y);
+       x += fast_reverse->get_w();
+       reverse_play->reposition_window(x, y);
+       x += reverse_play->get_w();
+       frame_reverse_play->reposition_window(x, y);
+       x += frame_reverse_play->get_w();
+       stop_button->reposition_window(x, y);
+       x += stop_button->get_w();
+       frame_forward_play->reposition_window(x, y);
+       x += frame_forward_play->get_w();
+       forward_play->reposition_window(x, y);
+       x += forward_play->get_w();
+       fast_play->reposition_window(x, y);
+       x += fast_play->get_w();
+       end_button->reposition_window(x, y);
+       x += end_button->get_w();
+}
+
+int PlayTransport::get_w()
+{
+       return end_button->get_x() + end_button->get_w() - rewind_button->get_x();
+}
+
+int PlayTransport::flip_vertical(int vertical, int &x, int &y)
+{
+       if(vertical)
+       {
+               rewind_button->reposition_window(x, y); 
+               y += rewind_button->get_h();
+               fast_reverse->reposition_window(x, y); 
+               y += fast_reverse->get_h();
+               reverse_play->reposition_window(x, y); 
+               y += reverse_play->get_h();
+               frame_reverse_play->reposition_window(x, y); 
+               y += frame_reverse_play->get_h();
+               stop_button->reposition_window(x, y); 
+               y += stop_button->get_h();
+               frame_forward_play->reposition_window(x, y); 
+               y += frame_forward_play->get_h();
+               forward_play->reposition_window(x, y); 
+               y += forward_play->get_h();
+               fast_play->reposition_window(x, y); 
+               y += fast_play->get_h();
+               end_button->reposition_window(x, y); 
+               y += end_button->get_h();
+       }
+       else
+       {
+               rewind_button->reposition_window(x, y - 2); 
+               x += rewind_button->get_w();
+               fast_reverse->reposition_window(x, y - 2); 
+               x += fast_reverse->get_w();
+               reverse_play->reposition_window(x, y - 2); 
+               x += reverse_play->get_w();
+               frame_reverse_play->reposition_window(x, y - 2); 
+               x += frame_reverse_play->get_w();
+               stop_button->reposition_window(x, y - 2); 
+               x += stop_button->get_w();
+               frame_forward_play->reposition_window(x, y - 2); 
+               x += frame_forward_play->get_w();
+               forward_play->reposition_window(x, y - 2); 
+               x += forward_play->get_w();
+               fast_play->reposition_window(x, y - 2); 
+               x += fast_play->get_w();
+               end_button->reposition_window(x, y - 2); 
+               x += end_button->get_w();
+       }
+
+       return 0;
+}
+
+int PlayTransport::keypress_event()
+{
+       int result = 1;
+       if(subwindow->shift_down())
+       {
+               switch(subwindow->get_keypress())
+               {
+                       case END:
+                               subwindow->lock_window("PlayTransport::keypress_event 1");
+                               goto_end();                                   
+                               subwindow->unlock_window();
+                               break;
+                       case HOME:
+                               subwindow->lock_window("PlayTransport::keypress_event 2");
+                               goto_start();                                 
+                               subwindow->unlock_window();
+                               break;
+                       default:
+                               result = 0;
+                               break;
+               }
+               return result;
+       }
+
+// Set playback range to in/out points if CTRL is down
+       int use_inout = 0;
+       if(subwindow->ctrl_down())
+       {
+               use_inout = 1;
+       }
+       using_inout = use_inout;
+       subwindow->unlock_window();
+
+
+       switch(subwindow->get_keypress())
+       {
+               case KPPLUS:    handle_transport(FAST_REWIND, 0, use_inout);            break;
+               case KP6:       handle_transport(NORMAL_REWIND, 0, use_inout);          break;
+               case KP5:       handle_transport(SLOW_REWIND, 0, use_inout);            break;
+               case KP4:       handle_transport(SINGLE_FRAME_REWIND, 0, use_inout);    break;
+               case KP1:       handle_transport(SINGLE_FRAME_FWD, 0, use_inout);       break;
+               case KP2:       handle_transport(SLOW_FWD, 0, use_inout);               break;
+               case KP3:       handle_transport(NORMAL_FWD, 0, use_inout);             break;
+               case KPENTER:   handle_transport(FAST_FWD, 0, use_inout);               break;
+               case KPINS:     handle_transport(STOP, 0, use_inout);                   break;
+               case ' ': {
+                       int prev_command = engine->command->command;
+                       int new_command = prev_command == COMMAND_NONE ||
+                                       prev_command == CURRENT_FRAME ||
+                                       prev_command == PAUSE ||
+                                       prev_command == STOP ? NORMAL_FWD : STOP;
+                               handle_transport(new_command, 0, use_inout);            break;
+                         }
+               case 'k':       handle_transport(STOP, 0, use_inout);                   break;
+               case END:
+                       subwindow->lock_window("PlayTransport::keypress_event 3");
+                       goto_end();                                   
+                       subwindow->unlock_window();
+                       break;
+               case HOME:
+                       subwindow->lock_window("PlayTransport::keypress_event 4");
+                       goto_start();                                 
+                       subwindow->unlock_window();
+                       break;
+               default:
+                       result = 0; 
+                       break;
+       }
+
+       subwindow->lock_window("PlayTransport::keypress_event 5");
+
+       return result;
+}
+
+
+void PlayTransport::goto_start()
+{
+       handle_transport(REWIND, 1, 0);
+}
+
+void PlayTransport::goto_end()
+{
+       handle_transport(GOTO_END, 1, 0);
+}
+
+
+
+void PlayTransport::handle_transport(int command, 
+       int wait_tracking,
+       int use_inout,
+       int update_refresh)
+{
+       if(!get_edl()) return;
+
+// Stop requires transferring the output buffer to a refresh buffer.
+       int do_stop = 0;
+//printf("PlayTransport::handle_transport 1 %d\n", command);
+       int prev_command = engine->command->command;
+       int prev_direction = engine->command->get_direction();
+       int prev_single_frame = engine->command->single_frame();
+
+// Dispatch command
+       switch(command)
+       {
+// Commands that play back
+               case FAST_REWIND:
+               case NORMAL_REWIND:
+               case SLOW_REWIND:
+               case SINGLE_FRAME_REWIND:
+               case SINGLE_FRAME_FWD:
+               case SLOW_FWD:
+               case NORMAL_FWD:
+               case FAST_FWD:
+// Same direction pressed twice.  Stop
+                       if(prev_command == command && 
+                               !prev_single_frame)
+                       {
+                               do_stop = 1;
+                       }
+                       else
+// Resume or change direction
+                       if(prev_command != STOP &&
+                               prev_command != COMMAND_NONE &&
+                               prev_command != SINGLE_FRAME_FWD &&
+                               prev_command != SINGLE_FRAME_REWIND)
+                       {
+                               engine->que->send_command(STOP,
+                                       CHANGE_NONE, 
+                                       0,
+                                       0,
+                                       0,
+                                       0);
+                               engine->interrupt_playback(wait_tracking);
+                               engine->que->send_command(command,
+                                       CHANGE_NONE, 
+                                       get_edl(),
+                                       1,
+                                       1,
+                                       use_inout);
+                       }
+                       else
+// Start from scratch
+                       {
+                               engine->que->send_command(command,
+                                       CHANGE_NONE, 
+                                       get_edl(),
+                                       1,
+                                       0,
+                                       use_inout);
+                       }
+                       break;
+
+// Commands that stop
+               case STOP:
+                       do_stop = 1;
+                       break;
+
+               case REWIND:
+               case GOTO_END:
+                       engine->que->send_command(STOP,
+                               CHANGE_NONE, 
+                               0,
+                               0,
+                               0,
+                               0);
+                       engine->interrupt_playback(wait_tracking);
+                       break;
+       }
+
+       if(do_stop)
+       {
+               engine->que->send_command(STOP,
+                       CHANGE_NONE, 
+                       0,
+                       0,
+                       0,
+                       0);
+               engine->interrupt_playback(wait_tracking);
+// This is necessary to get an OpenGL output buffer
+// printf("PlayTransport::handle_transport 2 update_refresh=%d prev_command=%d prev_direction=%d\n", 
+// update_refresh, prev_command, prev_direction);
+               if(!prev_single_frame && 
+                       update_refresh &&
+                       prev_command != STOP &&
+                       prev_command != COMMAND_NONE)
+               {
+                       engine->que->send_command(
+                               (prev_direction == PLAY_FORWARD) ? SINGLE_FRAME_REWIND : SINGLE_FRAME_FWD,
+                               CHANGE_NONE, 
+                               get_edl(),
+                               1,
+                               0,
+                               0);
+               }
+       }
+}
+
+EDL* PlayTransport::get_edl()
+{
+       return mwindow->edl;
+}
+
+int PlayTransport::pause_transport()
+{
+       if(active_button) active_button->set_mode(PLAY_MODE);
+       return 0;
+}
+
+
+int PlayTransport::reset_transport()
+{
+       fast_reverse->set_mode(PLAY_MODE);
+       reverse_play->set_mode(PLAY_MODE);
+       forward_play->set_mode(PLAY_MODE);
+       frame_reverse_play->set_mode(PLAY_MODE);
+       frame_forward_play->set_mode(PLAY_MODE);
+       fast_play->set_mode(PLAY_MODE);
+       return 0;
+}
+
+PTransportButton::PTransportButton(MWindow *mwindow, PlayTransport *transport, int x, int y, VFrame **data)
+ : BC_Button(x, y, data)
+{
+       this->mwindow = mwindow;
+       this->transport = transport;
+       mode = PLAY_MODE;
+}
+PTransportButton::~PTransportButton()
+{
+}
+
+int PTransportButton::set_mode(int mode)
+{
+       this->mode = mode;
+       return 0;
+}
+
+
+RewindButton::RewindButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("rewind"))
+{
+       set_tooltip(_("Rewind ( Home )"));
+}
+int RewindButton::handle_event()
+{
+//     unlock_window();
+       transport->goto_start();
+//     lock_window();
+       return 1;
+}
+
+FastReverseButton::FastReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastrev")) 
+{
+       set_tooltip(_("Fast reverse ( + )"));
+}
+int FastReverseButton::handle_event() 
+{
+       unlock_window();
+       transport->handle_transport(FAST_REWIND, 0, ctrl_down());
+       lock_window("FastReverseButton::handle_event");
+       return 1;
+}
+
+// Reverse playback normal speed
+
+ReverseButton::ReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("reverse")) 
+{
+       set_tooltip(_("Normal reverse ( 6 )"));
+}
+int ReverseButton::handle_event()
+{
+       unlock_window();
+       transport->handle_transport(NORMAL_REWIND, 0, ctrl_down());
+       lock_window("ReverseButton::handle_event");
+       return 1;
+}
+
+// Reverse playback one frame
+
+FrameReverseButton::FrameReverseButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framerev"))
+{
+       set_tooltip(_("Frame reverse ( 4 )"));
+}
+int FrameReverseButton::handle_event()
+{
+       unlock_window();
+       transport->handle_transport(SINGLE_FRAME_REWIND, 0, ctrl_down());
+       lock_window("FrameReverseButton::handle_event");
+       return 1;
+}
+
+// forward playback normal speed
+
+PlayButton::PlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("play")) 
+{
+       set_tooltip(_("Normal forward ( 3 )"));
+}
+int PlayButton::handle_event()
+{
+       unlock_window();
+       transport->handle_transport(NORMAL_FWD, 0, ctrl_down());
+       lock_window("PlayButton::handle_event");
+       return 1;
+}
+
+
+
+// forward playback one frame
+
+FramePlayButton::FramePlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("framefwd")) 
+{
+       set_tooltip(_("Frame forward ( 1 )"));
+}
+int FramePlayButton::handle_event()
+{
+       unlock_window();
+       transport->handle_transport(SINGLE_FRAME_FWD, 0, ctrl_down());
+       lock_window("FramePlayButton::handle_event");
+       return 1;
+}
+
+
+
+FastPlayButton::FastPlayButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("fastfwd")) 
+{
+       set_tooltip(_("Fast forward ( Enter )"));
+}
+int FastPlayButton::handle_event() 
+{
+       unlock_window();
+       transport->handle_transport(FAST_FWD, 0, ctrl_down());
+       lock_window("FastPlayButton::handle_event");
+       return 1;
+}
+
+EndButton::EndButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("end")) 
+{
+       set_tooltip(_("Jump to end ( End )"));
+}
+int EndButton::handle_event()
+{      
+//     unlock_window();
+       transport->goto_end();
+//     lock_window();
+       return 1;
+}
+
+StopButton::StopButton(MWindow *mwindow, PlayTransport *transport, int x, int y)
+ : PTransportButton(mwindow, transport, x, y, mwindow->theme->get_image_set("stop")) 
+{
+       set_tooltip(_("Stop ( 0 )"));
+}
+int StopButton::handle_event()
+{
+       unlock_window();
+       transport->handle_transport(STOP, 0, 0);
+       lock_window("StopButton::handle_event");
+       return 1;
+}
+
+
+
+void PlayTransport::change_position(double position)
+{
+       EDL *edl = get_edl();
+       if( !edl ) return;
+       int prev_command = engine->command->command;
+// stop transport
+       if( prev_command != STOP && prev_command != COMMAND_NONE &&
+           prev_command != SINGLE_FRAME_FWD && prev_command != SINGLE_FRAME_REWIND ) {
+               engine->que->send_command(STOP, CHANGE_NONE, 0, 0, 0, 0);
+               engine->interrupt_playback(0);
+       }
+       mwindow->gui->lock_window("PlayTransport::change_position");
+       mwindow->goto_position(position);
+       mwindow->gui->unlock_window();
+// restart command
+       switch(prev_command) {
+       case FAST_REWIND:
+       case NORMAL_REWIND:
+       case SLOW_REWIND:
+       case SLOW_FWD:
+       case NORMAL_FWD:
+       case FAST_FWD:
+               engine->que->send_command(prev_command, CHANGE_NONE,
+                               get_edl(), 1, 1, using_inout);
+       }
+}
+