4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "awindowgui.h"
32 #include "edlsession.h"
33 #include "filesystem.h"
40 #include "localsession.h"
41 #include "mainclock.h"
43 #include "mainsession.h"
45 #include "meterpanel.h"
46 #include "mwindowgui.h"
48 #include "playtransport.h"
49 #include "preferences.h"
50 #include "renderengine.h"
55 #include "transportque.h"
57 #include "vplayback.h"
59 #include "vwindowgui.h"
65 VWindowGUI::VWindowGUI(MWindow *mwindow, VWindow *vwindow)
66 : BC_Window(_(PROGRAM_NAME ": Viewer"),
67 mwindow->session->vwindow_x,
68 mwindow->session->vwindow_y,
69 mwindow->session->vwindow_w,
70 mwindow->session->vwindow_h,
77 this->mwindow = mwindow;
78 this->vwindow = vwindow;
84 strcpy(loaded_title, "");
88 VWindowGUI::~VWindowGUI()
90 vwindow->stop_playback(1);
91 sources.remove_all_objects();
92 labels.remove_all_objects();
100 void VWindowGUI::draw_wave()
102 TransportCommand command;
103 command.command = NORMAL_FWD;
104 command.get_edl()->copy_all(vwindow->get_edl());
105 command.change_type = CHANGE_ALL;
106 command.realtime = 0;
107 RenderEngine *render_engine = new RenderEngine(0, mwindow->preferences, 0, 0);
108 CICache *cache = new CICache(mwindow->preferences);
109 render_engine->set_acache(cache);
110 render_engine->arm_command(&command);
112 double duration = 1.;
113 int w = mwindow->edl->session->output_w;
114 int h = mwindow->edl->session->output_h;
115 VFrame *vframe = new VFrame(w, h, BC_RGB888);
116 vframe->clear_frame();
117 int sample_rate = mwindow->edl->get_sample_rate();
118 int channels = mwindow->edl->session->audio_channels;
119 if( channels > 2 ) channels = 2;
120 int64_t bfrsz = sample_rate * duration;
121 Samples *samples[MAXCHANNELS];
123 while( ch < channels ) samples[ch++] = new Samples(bfrsz);
124 while( ch < MAXCHANNELS ) samples[ch++] = 0;
125 render_engine->arender->process_buffer(samples, bfrsz, 0);
127 static int line_colors[2] = { GREEN, YELLOW };
128 static int base_colors[2] = { RED, PINK };
129 for( int i=channels; --i>=0; ) {
130 AssetPicon::draw_wave(vframe, samples[i]->get_data(), bfrsz,
131 base_colors[i], line_colors[i]);
134 for( int i=channels; --i>=0; ) delete samples[i];
135 delete render_engine;
137 delete canvas->refresh_frame;
138 canvas->refresh_frame = vframe;
142 void VWindowGUI::change_source(EDL *edl, const char *title)
144 //printf("VWindowGUI::change_source %d\n", __LINE__);
146 update_sources(title);
147 strcpy(loaded_title, title);
148 char string[BCTEXTLEN];
150 sprintf(string, _(PROGRAM_NAME ": %s"), title);
152 sprintf(string, _(PROGRAM_NAME ": Viewer"));
154 lock_window("VWindowGUI::change_source");
157 !edl->tracks->playable_video_tracks() &&
158 edl->tracks->playable_audio_tracks() )
166 // Get source list from master EDL
167 void VWindowGUI::update_sources(const char *title)
169 lock_window("VWindowGUI::update_sources");
170 sources.remove_all_objects();
172 for( int i=0; i<mwindow->edl->clips.size(); ++i ) {
173 char *clip_title = mwindow->edl->clips.values[i]->local_session->clip_title;
176 for( int j=0; !exists && j<sources.size(); ++j ) {
177 if( !strcasecmp(sources.values[j]->get_text(), clip_title) )
182 sources.append(new BC_ListBoxItem(clip_title));
186 for( Asset *current=mwindow->edl->assets->first; current; current=NEXT ) {
187 char clip_title[BCTEXTLEN];
188 fs.extract_name(clip_title, current->path);
191 for( int j=0; !exists && j<sources.size(); ++j ) {
192 if( !strcasecmp(sources.values[j]->get_text(), clip_title) )
197 sources.append(new BC_ListBoxItem(clip_title));
203 void VWindowGUI::create_objects()
205 lock_window("VWindowGUI::create_objects");
208 set_icon(mwindow->theme->get_image("vwindow_icon"));
210 //printf("VWindowGUI::create_objects 1\n");
211 mwindow->theme->get_vwindow_sizes(this);
212 mwindow->theme->draw_vwindow_bg(this);
215 meters = new VWindowMeters(mwindow,
217 mwindow->theme->vmeter_x,
218 mwindow->theme->vmeter_y,
219 mwindow->theme->vmeter_h);
220 meters->create_objects();
222 //printf("VWindowGUI::create_objects 1\n");
223 // Requires meters to build
224 edit_panel = new VWindowEditing(mwindow, vwindow);
225 edit_panel->set_meters(meters);
226 edit_panel->create_objects();
228 //printf("VWindowGUI::create_objects 1\n");
229 transport = new VWindowTransport(mwindow,
231 mwindow->theme->vtransport_x,
232 mwindow->theme->vtransport_y);
233 transport->create_objects();
235 //printf("VWindowGUI::create_objects 1\n");
236 // add_subwindow(fps_title = new BC_Title(mwindow->theme->vedit_x, y, ""));
237 add_subwindow(clock = new MainClock(mwindow,
238 mwindow->theme->vtime_x,
239 mwindow->theme->vtime_y,
240 mwindow->theme->vtime_w));
242 canvas = new VWindowCanvas(mwindow, this);
243 canvas->create_objects(mwindow->edl);
244 canvas->use_vwindow();
245 char vsplash_path[BCTEXTLEN];
246 int vsplash_len = sizeof(vsplash_path)-1;
247 snprintf(vsplash_path, vsplash_len, "%s/vsplash.png", File::get_cindat_path());
248 VFrame *vsplash = VFramePng::vframe_png(vsplash_path);
250 BC_WindowBase *vcanvas = canvas->get_canvas();
251 vcanvas->draw_vframe(vsplash,
252 0,0, vcanvas->get_w(), vcanvas->get_h(),
253 0,0, vsplash->get_w(), vsplash->get_h(), 0);
257 //printf("VWindowGUI::create_objects 1\n");
258 add_subwindow(timebar = new VTimeBar(mwindow,
260 mwindow->theme->vtimebar_x,
261 mwindow->theme->vtimebar_y,
262 mwindow->theme->vtimebar_w,
263 mwindow->theme->vtimebar_h));
264 timebar->create_objects();
265 //printf("VWindowGUI::create_objects 2\n");
268 //printf("VWindowGUI::create_objects 1\n");
269 // source = new VWindowSource(mwindow,
271 // mwindow->theme->vsource_x,
272 // mwindow->theme->vsource_y);
273 // source->create_objects();
274 update_sources(_("None"));
276 //printf("VWindowGUI::create_objects 2\n");
283 int VWindowGUI::resize_event(int w, int h)
285 mwindow->session->vwindow_x = get_x();
286 mwindow->session->vwindow_y = get_y();
287 mwindow->session->vwindow_w = w;
288 mwindow->session->vwindow_h = h;
290 mwindow->theme->get_vwindow_sizes(this);
291 mwindow->theme->draw_vwindow_bg(this);
294 //printf("VWindowGUI::resize_event %d %d\n", __LINE__, mwindow->theme->vedit_y);
295 edit_panel->reposition_buttons(mwindow->theme->vedit_x,
296 mwindow->theme->vedit_y);
298 timebar->resize_event();
299 transport->reposition_buttons(mwindow->theme->vtransport_x,
300 mwindow->theme->vtransport_y);
301 clock->reposition_window(mwindow->theme->vtime_x,
302 mwindow->theme->vtime_y,
303 mwindow->theme->vtime_w,
305 canvas->reposition_window(0,
306 mwindow->theme->vcanvas_x,
307 mwindow->theme->vcanvas_y,
308 mwindow->theme->vcanvas_w,
309 mwindow->theme->vcanvas_h);
310 //printf("VWindowGUI::resize_event %d %d\n", __LINE__, mwindow->theme->vcanvas_x);
311 // source->reposition_window(mwindow->theme->vsource_x,
312 // mwindow->theme->vsource_y);
313 meters->reposition_window(mwindow->theme->vmeter_x,
314 mwindow->theme->vmeter_y,
316 mwindow->theme->vmeter_h);
318 BC_WindowBase::resize_event(w, h);
326 int VWindowGUI::translation_event()
328 mwindow->session->vwindow_x = get_x();
329 mwindow->session->vwindow_y = get_y();
333 int VWindowGUI::close_event()
336 int i = mwindow->vwindows.size();
337 while( --i >= 0 && mwindow->vwindows.get(i)->gui != this );
343 mwindow->session->show_vwindow = 0;
346 mwindow->gui->lock_window("VWindowGUI::close_event");
347 mwindow->gui->mainmenu->show_vwindow->set_checked(0);
348 mwindow->gui->unlock_window();
350 lock_window("VWindowGUI::close_event");
351 mwindow->save_defaults();
355 int VWindowGUI::keypress_event()
358 switch( get_keypress() ) {
365 mwindow->undo_entry(this);
368 mwindow->redo_entry(this);
372 if( canvas->get_fullscreen() )
373 canvas->stop_fullscreen();
375 canvas->start_fullscreen();
376 lock_window("VWindowGUI::keypress_event 1");
380 if( canvas->get_fullscreen() )
381 canvas->stop_fullscreen();
382 lock_window("VWindowGUI::keypress_event 2");
388 if( ctrl_down() && shift_down() ) {
389 resend_event(mwindow->gui);
395 result = transport->keypress_event();
399 int VWindowGUI::button_press_event()
401 if( vwindow->get_edl() != 0 && canvas->get_canvas() &&
402 mwindow->edl->session->vwindow_click2play &&
403 canvas->get_canvas()->get_cursor_over_window() ) {
404 switch( get_buttonpress() ) {
406 if( !vwindow->playback_engine->is_playing_back ) {
407 double length = vwindow->get_edl()->tracks->total_playable_length();
408 double position = vwindow->playback_engine->get_tracking_position();
409 if( position >= length ) transport->goto_start();
411 return transport->forward_play->handle_event();
413 if( !vwindow->playback_engine->is_playing_back ) {
414 double position = vwindow->playback_engine->get_tracking_position();
415 if( position <= 0 ) transport->goto_end();
417 return transport->reverse_play->handle_event();
418 case RIGHT_BUTTON: // activates popup
421 return transport->frame_forward_play->handle_event();
423 return transport->frame_reverse_play->handle_event();
426 if(canvas->get_canvas())
427 return canvas->button_press_event_base(canvas->get_canvas());
431 int VWindowGUI::cursor_leave_event()
433 if(canvas->get_canvas())
434 return canvas->cursor_leave_event_base(canvas->get_canvas());
438 int VWindowGUI::cursor_enter_event()
440 if(canvas->get_canvas())
441 return canvas->cursor_enter_event_base(canvas->get_canvas());
445 int VWindowGUI::button_release_event()
447 if(canvas->get_canvas())
448 return canvas->button_release_event();
452 int VWindowGUI::cursor_motion_event()
454 if(canvas->get_canvas())
456 canvas->get_canvas()->unhide_cursor();
457 return canvas->cursor_motion_event();
463 void VWindowGUI::drag_motion()
466 if(get_hidden()) return;
467 if(mwindow->session->current_operation != DRAG_ASSET) return;
468 int need_highlight = cursor_above() && get_cursor_over_window() ? 1 : 0;
469 if( highlighted == need_highlight ) return;
470 highlighted = need_highlight;
474 int VWindowGUI::drag_stop()
476 if( get_hidden() ) return 0;
479 mwindow->session->current_operation == DRAG_ASSET ) {
484 Indexable *indexable =
485 mwindow->session->drag_assets->size() > 0 ?
486 (Indexable *)mwindow->session->drag_assets->get(0) :
487 mwindow->session->drag_clips->size() > 0 ?
488 (Indexable *)mwindow->session->drag_clips->get(0) : 0;
490 vwindow->change_source(indexable);
492 lock_window("VWindowGUI::drag_stop");
499 void VWindowGUI::stop_transport()
501 if( !transport->is_stopped() ) {
503 transport->handle_transport(STOP, 1);
504 lock_window("VWindowGUI::panel_stop_transport");
508 void VWindowGUI::update_meters()
510 if(mwindow->edl->session->vwindow_meter != meters->visible)
512 meters->set_meters(meters->meter_count,
513 mwindow->edl->session->vwindow_meter);
514 mwindow->theme->get_vwindow_sizes(this);
515 resize_event(get_w(), get_h());
521 VWindowMeters::VWindowMeters(MWindow *mwindow,
526 : MeterPanel(mwindow,
532 mwindow->edl->session->audio_channels,
533 mwindow->edl->session->vwindow_meter,
537 this->mwindow = mwindow;
541 VWindowMeters::~VWindowMeters()
545 int VWindowMeters::change_status_event(int new_status)
547 mwindow->edl->session->vwindow_meter = new_status;
548 gui->update_meters();
553 VWindowEditing::VWindowEditing(MWindow *mwindow, VWindow *vwindow)
554 : EditPanel(mwindow, vwindow->gui, VWINDOW_ID,
555 mwindow->theme->vedit_x, mwindow->theme->vedit_y,
557 0, // use_editing_mode
574 this->mwindow = mwindow;
575 this->vwindow = vwindow;
578 VWindowEditing::~VWindowEditing()
582 #define relock_vm(s) \
583 vwindow->gui->unlock_window(); \
584 mwindow->gui->lock_window("VWindowEditing::" s)
585 #define relock_mv(s) \
586 mwindow->gui->unlock_window(); \
587 vwindow->gui->lock_window("VWindowEditing::" s)
589 double VWindowEditing::get_position()
591 EDL *edl = vwindow->get_edl();
592 double position = !edl ? 0 : edl->local_session->get_selectionstart(1);
596 void VWindowEditing::set_position(double position)
598 EDL *edl = vwindow->get_edl();
600 if( get_position() != position ) {
601 if( position < 0 ) position = 0;
602 edl->local_session->set_selectionstart(position);
603 edl->local_session->set_selectionend(position);
604 vwindow->update_position();
608 void VWindowEditing::set_click_to_play(int v)
610 click2play->update(v);
611 relock_vm("set_click_to_play");
612 mwindow->edl->session->vwindow_click2play = v;
613 mwindow->update_vwindow();
614 relock_mv("set_click_to_play");
617 void VWindowEditing::panel_stop_transport()
619 vwindow->gui->stop_transport();
622 void VWindowEditing::panel_toggle_label()
624 if( !vwindow->get_edl() ) return;
625 EDL *edl = vwindow->get_edl();
626 edl->labels->toggle_label(edl->local_session->get_selectionstart(1),
627 edl->local_session->get_selectionend(1));
628 vwindow->gui->timebar->update(1);
631 void VWindowEditing::panel_next_label(int cut)
633 if( !vwindow->get_edl() ) return;
634 vwindow->interrupt_playback(1);
636 EDL *edl = vwindow->get_edl();
637 Label *current = edl->labels->next_label(
638 edl->local_session->get_selectionstart(1));
639 double position = current ? current->position :
640 edl->tracks->total_length();
641 edl->local_session->set_selectionstart(position);
642 edl->local_session->set_selectionend(position);
643 vwindow->update_position();
644 vwindow->gui->timebar->update(1);
647 void VWindowEditing::panel_prev_label(int cut)
649 if( !vwindow->get_edl() ) return;
650 vwindow->interrupt_playback(1);
652 EDL *edl = vwindow->get_edl();
653 Label *current = edl->labels->prev_label(
654 edl->local_session->get_selectionstart(1));
655 double position = !current ? 0 : current->position;
656 edl->local_session->set_selectionstart(position);
657 edl->local_session->set_selectionend(position);
658 vwindow->update_position();
659 vwindow->gui->timebar->update(1);
662 void VWindowEditing::panel_prev_edit(int cut) {} // not used
663 void VWindowEditing::panel_next_edit(int cut) {} // not used
665 void VWindowEditing::panel_copy_selection()
667 vwindow->copy(vwindow->gui->shift_down());
670 void VWindowEditing::panel_overwrite_selection()
672 if( !vwindow->get_edl() ) return;
673 relock_vm("overwrite_selection");
674 mwindow->overwrite(vwindow->get_edl(), vwindow->gui->shift_down());
675 relock_mv("overwrite_selection");
678 void VWindowEditing::panel_splice_selection()
680 if( !vwindow->get_edl() ) return;
681 relock_vm("splice_selection");
682 mwindow->splice(vwindow->get_edl(), vwindow->gui->shift_down());
683 relock_mv("splice_selection");
686 void VWindowEditing::panel_set_inpoint()
688 vwindow->set_inpoint();
691 void VWindowEditing::panel_set_outpoint()
693 vwindow->set_outpoint();
696 void VWindowEditing::panel_unset_inoutpoint()
698 vwindow->unset_inoutpoint();
701 void VWindowEditing::panel_to_clip()
703 EDL *edl = vwindow->get_edl();
705 mwindow->to_clip(edl, _("viewer window: "), subwindow->shift_down());
709 void VWindowEditing::panel_cut() {}
710 void VWindowEditing::panel_paste() {}
711 void VWindowEditing::panel_fit_selection() {}
712 void VWindowEditing::panel_fit_autos(int all) {}
713 void VWindowEditing::panel_set_editing_mode(int mode) {}
714 void VWindowEditing::panel_set_auto_keyframes(int v) {}
715 void VWindowEditing::panel_set_span_keyframes(int v) {}
716 void VWindowEditing::panel_set_labels_follow_edits(int v) {}
719 VWindowSource::VWindowSource(MWindow *mwindow, VWindowGUI *vwindow, int x, int y)
720 : BC_PopupTextBox(vwindow,
728 this->mwindow = mwindow;
729 this->vwindow = vwindow;
732 VWindowSource::~VWindowSource()
736 int VWindowSource::handle_event()
742 VWindowTransport::VWindowTransport(MWindow *mwindow,
746 : PlayTransport(mwindow,
754 EDL* VWindowTransport::get_edl()
756 return gui->vwindow->get_edl();
760 void VWindowTransport::goto_start()
762 gui->unlock_window();
763 handle_transport(REWIND, 1);
764 gui->lock_window("VWindowTransport::goto_start");
765 gui->vwindow->goto_start();
768 void VWindowTransport::goto_end()
770 gui->unlock_window();
771 handle_transport(GOTO_END, 1);
772 gui->lock_window("VWindowTransport::goto_end");
773 gui->vwindow->goto_end();
779 VWindowCanvas::VWindowCanvas(MWindow *mwindow, VWindowGUI *gui)
782 mwindow->theme->vcanvas_x,
783 mwindow->theme->vcanvas_y,
784 mwindow->theme->vcanvas_w,
785 mwindow->theme->vcanvas_h,
788 //printf("VWindowCanvas::VWindowCanvas %d %d\n", __LINE__, mwindow->theme->vcanvas_x);
789 this->mwindow = mwindow;
793 void VWindowCanvas::zoom_resize_window(float percentage)
795 EDL *edl = gui->vwindow->get_edl();
796 if(!edl) edl = mwindow->edl;
798 int canvas_w, canvas_h;
801 // Get required canvas size
802 calculate_sizes(edl->get_aspect_ratio(),
803 edl->session->output_w,
804 edl->session->output_h,
809 // Estimate window size from current borders
810 new_w = canvas_w + (gui->get_w() - mwindow->theme->vcanvas_w);
811 new_h = canvas_h + (gui->get_h() - mwindow->theme->vcanvas_h);
813 mwindow->session->vwindow_w = new_w;
814 mwindow->session->vwindow_h = new_h;
816 mwindow->theme->get_vwindow_sizes(gui);
818 // Estimate again from new borders
819 new_w = canvas_w + (mwindow->session->vwindow_w - mwindow->theme->vcanvas_w);
820 new_h = canvas_h + (mwindow->session->vwindow_h - mwindow->theme->vcanvas_h);
823 gui->resize_window(new_w, new_h);
824 gui->resize_event(new_w, new_h);
827 void VWindowCanvas::close_source()
829 gui->vwindow->interrupt_playback(1);
830 gui->vwindow->delete_source(1, 1);
834 void VWindowCanvas::draw_refresh(int flush)
836 EDL *edl = gui->vwindow->get_edl();
838 if( !get_canvas()->get_video_on() ) {
839 int cw = get_canvas()->get_w(), ch = get_canvas()->get_h();
840 get_canvas()->clear_box(0, 0, cw, ch);
841 int ow = get_output_w(edl), oh = get_output_h(edl);
842 if( ow > 0 && oh > 0 && refresh_frame && edl ) {
843 float in_x1, in_y1, in_x2, in_y2;
844 float out_x1, out_y1, out_x2, out_y2;
846 in_x1, in_y1, in_x2, in_y2,
847 out_x1, out_y1, out_x2, out_y2);
848 // input scaled from session to refresh frame coordinates
849 int rw = refresh_frame->get_w();
850 int rh = refresh_frame->get_h();
851 float xs = (float)rw / ow;
852 float ys = (float)rh / oh;
853 in_x1 *= xs; in_x2 *= xs;
854 in_y1 *= ys; in_y2 *= ys;
855 get_canvas()->draw_vframe(refresh_frame,
856 (int)out_x1, (int)out_y1,
857 (int)(out_x2 - out_x1), (int)(out_y2 - out_y1),
858 (int)in_x1, (int)in_y1,
859 (int)(in_x2 - in_x1), (int)(in_y2 - in_y1),
863 get_canvas()->flash(flush);
867 int VWindowCanvas::need_overlays()
869 if( gui->highlighted ) return 1;
873 void VWindowCanvas::draw_overlays()
875 if( gui->highlighted )
877 get_canvas()->set_color(WHITE);
878 get_canvas()->set_inverse();
879 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
880 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
881 get_canvas()->set_opaque();