prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / transportque.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 "bcsignals.h"
23 #include "clip.h"
24 #include "condition.h"
25 #include "edl.h"
26 #include "edlsession.h"
27 #include "localsession.h"
28 #include "tracks.h"
29 #include "transportque.h"
30
31 TransportCommand::TransportCommand()
32 {
33 // In rendering we want a master EDL so settings don't get clobbered
34 // in the middle of a job.
35         edl = new EDL;
36         edl->create_objects();
37         command = 0;
38         change_type = 0;
39         reset();
40 }
41
42 TransportCommand::~TransportCommand()
43 {
44         edl->Garbage::remove_user();
45 }
46
47 void TransportCommand::reset()
48 {
49         playbackstart = 0;
50         start_position = 0;
51         end_position = 0;
52         infinite = 0;
53         realtime = 0;
54         resume = 0;
55 // Don't reset the change type for commands which don't perform the change
56         if(command != STOP) change_type = 0;
57         command = COMMAND_NONE;
58 }
59
60 EDL* TransportCommand::get_edl()
61 {
62         return edl;
63 }
64
65 void TransportCommand::delete_edl()
66 {
67         edl->Garbage::remove_user();
68         edl = 0;
69 }
70
71 void TransportCommand::new_edl()
72 {
73         edl = new EDL;
74         edl->create_objects();
75 }
76
77
78 void TransportCommand::copy_from(TransportCommand *command)
79 {
80         this->command = command->command;
81         this->change_type = command->change_type;
82         this->edl->copy_all(command->edl);
83         this->start_position = command->start_position;
84         this->end_position = command->end_position;
85         this->playbackstart = command->playbackstart;
86         this->realtime = command->realtime;
87         this->resume = command->resume;
88 }
89
90 TransportCommand& TransportCommand::operator=(TransportCommand &command)
91 {
92         copy_from(&command);
93         return *this;
94 }
95
96 int TransportCommand::single_frame()
97 {
98         return (command == SINGLE_FRAME_FWD ||
99                 command == SINGLE_FRAME_REWIND ||
100                 command == CURRENT_FRAME);
101 }
102
103
104 int TransportCommand::get_direction()
105 {
106         switch(command)
107         {
108                 case SINGLE_FRAME_FWD:
109                 case NORMAL_FWD:
110                 case FAST_FWD:
111                 case SLOW_FWD:
112                 case CURRENT_FRAME:
113                         return PLAY_FORWARD;
114                         break;
115
116                 case SINGLE_FRAME_REWIND:
117                 case NORMAL_REWIND:
118                 case FAST_REWIND:
119                 case SLOW_REWIND:
120                         return PLAY_REVERSE;
121                         break;
122
123                 default:
124                         return PLAY_FORWARD;
125                         break;
126         }
127 }
128
129 float TransportCommand::get_speed()
130 {
131         switch(command)
132         {
133                 case SLOW_FWD:
134                 case SLOW_REWIND:
135                         return 0.5;
136                 
137                 case NORMAL_FWD:
138                 case NORMAL_REWIND:
139                 case SINGLE_FRAME_FWD:
140                 case SINGLE_FRAME_REWIND:
141                 case CURRENT_FRAME:
142                         return 1.;
143                 
144                 case FAST_FWD:
145                 case FAST_REWIND:
146                         return 2.;
147         }
148
149         return 0.;
150 }
151
152 // Assume starting without pause
153 void TransportCommand::set_playback_range(EDL *edl, int use_inout)
154 {
155         if(!edl) edl = this->edl;
156
157
158
159
160         switch(command)
161         {
162                 case SLOW_FWD:
163                 case FAST_FWD:
164                 case NORMAL_FWD:
165                         start_position = edl->local_session->get_selectionstart(1);
166                         if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
167                                 end_position = edl->tracks->total_playable_length();
168                         else
169                                 end_position = edl->local_session->get_selectionend(1);
170 // this prevents a crash if start position is after the loop when playing forwards
171                     if (edl->local_session->loop_playback && 
172                                 start_position > edl->local_session->loop_end)  
173                         {
174                                     start_position = edl->local_session->loop_start;
175                         }
176                         break;
177                 
178                 case SLOW_REWIND:
179                 case FAST_REWIND:
180                 case NORMAL_REWIND:
181                         end_position = edl->local_session->get_selectionend(1);
182                         if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
183                                 start_position = 0;
184                         else
185                                 start_position = edl->local_session->get_selectionstart(1);
186
187 // this prevents a crash if start position is before the loop when playing backwards
188                         if (edl->local_session->loop_playback && 
189                                 end_position <= edl->local_session->loop_start)
190                         {
191                                         end_position = edl->local_session->loop_end;
192                         }
193                         break;
194                 
195                 case CURRENT_FRAME:
196                 case SINGLE_FRAME_FWD:
197                         start_position = edl->local_session->get_selectionstart(1);
198                         end_position = start_position + 
199                                 1.0 / 
200                                 edl->session->frame_rate;
201                         break;
202                 
203                 case SINGLE_FRAME_REWIND:
204                         start_position = edl->local_session->get_selectionend(1);
205                         end_position = start_position - 
206                                 1.0 / 
207                                 edl->session->frame_rate;
208                         break;
209         }
210
211
212         if(use_inout)
213         {
214                 if(edl->local_session->inpoint_valid())
215                         start_position = edl->local_session->get_inpoint();
216                 if(edl->local_session->outpoint_valid())
217                         end_position = edl->local_session->get_outpoint();
218         }
219
220         switch(get_direction())
221         {
222                 case PLAY_FORWARD:
223                         playbackstart = start_position;
224                         break;
225
226                 case PLAY_REVERSE:
227                         playbackstart = end_position;
228                         break;
229         }
230
231 }
232
233 void TransportCommand::adjust_playback_range()
234 {
235
236
237         if(edl->local_session->inpoint_valid() ||
238                 edl->local_session->outpoint_valid())
239         {
240                 if(edl->local_session->inpoint_valid())
241                         start_position = edl->local_session->get_inpoint();
242                 else
243                         start_position = 0;
244
245                 if(edl->local_session->outpoint_valid())
246                         end_position = edl->local_session->get_outpoint();
247                 else
248                         end_position = edl->tracks->total_playable_length();
249         }
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 TransportQue::TransportQue()
270 {
271         input_lock = new Condition(1, "TransportQue::input_lock");
272         output_lock = new Condition(0, "TransportQue::output_lock", 1);
273 }
274
275 TransportQue::~TransportQue()
276 {
277         delete input_lock;
278         delete output_lock;
279 }
280
281 int TransportQue::send_command(int command, 
282                 int change_type, 
283                 EDL *new_edl, 
284                 int realtime,
285                 int resume,
286                 int use_inout)
287 {
288         input_lock->lock("TransportQue::send_command 1");
289         this->command.command = command;
290 // Mutually exclusive operation
291         this->command.change_type |= change_type;
292         this->command.realtime = realtime;
293         this->command.resume = resume;
294
295         if(new_edl)
296         {
297 // Just change the EDL if the change requires it because renderengine
298 // structures won't point to the new EDL otherwise and because copying the
299 // EDL for every cursor movement is slow.
300                 if(change_type == CHANGE_EDL ||
301                         (uint32_t)change_type == CHANGE_ALL)
302                 {
303 // Copy EDL
304                         this->command.get_edl()->copy_all(new_edl);
305                 }
306                 else
307                 if(change_type == CHANGE_PARAMS)
308                 {
309                         this->command.get_edl()->synchronize_params(new_edl);
310                 }
311
312 // Set playback range
313                 this->command.set_playback_range(new_edl, use_inout);
314         }
315
316         input_lock->unlock();
317
318         output_lock->unlock();
319         return 0;
320 }
321
322 void TransportQue::update_change_type(int change_type)
323 {
324         input_lock->lock("TransportQue::update_change_type");
325         this->command.change_type |= change_type;
326         input_lock->unlock();
327 }