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,
71 xS(100), yS(100), 1, 1, 0) // Hide it
73 this->mwindow = mwindow;
74 this->vwindow = vwindow;
80 strcpy(loaded_title, "");
84 VWindowGUI::~VWindowGUI()
86 vwindow->stop_playback(1);
87 sources.remove_all_objects();
88 labels.remove_all_objects();
96 void VWindowGUI::draw_wave()
98 TransportCommand command;
99 command.command = NORMAL_FWD;
100 command.get_edl()->copy_all(vwindow->get_edl());
101 command.change_type = CHANGE_ALL;
102 command.realtime = 0;
103 RenderEngine *render_engine = new RenderEngine(0, mwindow->preferences, 0, 0);
104 CICache *cache = new CICache(mwindow->preferences);
105 render_engine->set_acache(cache);
106 render_engine->arm_command(&command);
108 double duration = 1.;
109 int w = mwindow->edl->session->output_w;
110 int h = mwindow->edl->session->output_h;
111 VFrame *vframe = new VFrame(w, h, BC_RGB888);
112 vframe->clear_frame();
113 int sample_rate = mwindow->edl->get_sample_rate();
114 int channels = mwindow->edl->session->audio_channels;
115 if( channels > 2 ) channels = 2;
116 int64_t bfrsz = sample_rate * duration;
117 Samples *samples[MAXCHANNELS];
119 while( ch < channels ) samples[ch++] = new Samples(bfrsz);
120 while( ch < MAXCHANNELS ) samples[ch++] = 0;
121 render_engine->arender->process_buffer(samples, bfrsz, 0);
123 static int line_colors[2] = { GREEN, YELLOW };
124 static int base_colors[2] = { RED, PINK };
125 for( int i=channels; --i>=0; ) {
126 AssetPicon::draw_wave(vframe, samples[i]->get_data(), bfrsz,
127 base_colors[i], line_colors[i]);
130 for( int i=channels; --i>=0; ) delete samples[i];
131 delete render_engine;
133 delete canvas->refresh_frame;
134 canvas->refresh_frame = vframe;
138 void VWindowGUI::change_source(EDL *edl, const char *title)
140 //printf("VWindowGUI::change_source %d\n", __LINE__);
142 update_sources(title);
143 strcpy(loaded_title, title);
144 char string[BCTEXTLEN];
146 sprintf(string, _(PROGRAM_NAME ": %s"), title);
148 sprintf(string, _(PROGRAM_NAME ": Viewer"));
150 lock_window("VWindowGUI::change_source");
153 !edl->tracks->playable_video_tracks() &&
154 edl->tracks->playable_audio_tracks() )
162 // Get source list from master EDL
163 void VWindowGUI::update_sources(const char *title)
165 lock_window("VWindowGUI::update_sources");
166 sources.remove_all_objects();
168 for( int i=0; i<mwindow->edl->clips.size(); ++i ) {
169 char *clip_title = mwindow->edl->clips.values[i]->local_session->clip_title;
172 for( int j=0; !exists && j<sources.size(); ++j ) {
173 if( !strcasecmp(sources.values[j]->get_text(), clip_title) )
178 sources.append(new BC_ListBoxItem(clip_title));
182 for( Asset *current=mwindow->edl->assets->first; current; current=NEXT ) {
183 char clip_title[BCTEXTLEN];
184 fs.extract_name(clip_title, current->path);
187 for( int j=0; !exists && j<sources.size(); ++j ) {
188 if( !strcasecmp(sources.values[j]->get_text(), clip_title) )
193 sources.append(new BC_ListBoxItem(clip_title));
199 void VWindowGUI::create_objects()
201 lock_window("VWindowGUI::create_objects");
204 set_icon(mwindow->theme->get_image("vwindow_icon"));
206 //printf("VWindowGUI::create_objects 1\n");
207 mwindow->theme->get_vwindow_sizes(this);
208 mwindow->theme->draw_vwindow_bg(this);
211 meters = new VWindowMeters(mwindow,
213 mwindow->theme->vmeter_x,
214 mwindow->theme->vmeter_y,
215 mwindow->theme->vmeter_h);
216 meters->create_objects();
218 //printf("VWindowGUI::create_objects 1\n");
219 // Requires meters to build
220 edit_panel = new VWindowEditing(mwindow, vwindow);
221 edit_panel->set_meters(meters);
222 edit_panel->create_objects();
224 //printf("VWindowGUI::create_objects 1\n");
225 transport = new VWindowTransport(mwindow,
227 mwindow->theme->vtransport_x,
228 mwindow->theme->vtransport_y);
229 transport->create_objects();
231 //printf("VWindowGUI::create_objects 1\n");
232 // add_subwindow(fps_title = new BC_Title(mwindow->theme->vedit_x, y, ""));
233 add_subwindow(clock = new MainClock(mwindow,
234 mwindow->theme->vtime_x,
235 mwindow->theme->vtime_y,
236 mwindow->theme->vtime_w));
238 canvas = new VWindowCanvas(mwindow, this);
239 canvas->create_objects(mwindow->edl);
240 char vsplash_path[BCTEXTLEN];
241 int vsplash_len = sizeof(vsplash_path)-1;
242 snprintf(vsplash_path, vsplash_len, "%s/vsplash.png", File::get_cindat_path());
243 VFrame *vsplash = VFramePng::vframe_png(vsplash_path);
245 BC_WindowBase *vcanvas = canvas->get_canvas();
246 vcanvas->draw_vframe(vsplash,
247 0,0, vcanvas->get_w(), vcanvas->get_h(),
248 0,0, vsplash->get_w(), vsplash->get_h(), 0);
252 //printf("VWindowGUI::create_objects 1\n");
253 add_subwindow(timebar = new VTimeBar(mwindow,
255 mwindow->theme->vtimebar_x,
256 mwindow->theme->vtimebar_y,
257 mwindow->theme->vtimebar_w,
258 mwindow->theme->vtimebar_h));
259 timebar->create_objects();
260 //printf("VWindowGUI::create_objects 2\n");
263 //printf("VWindowGUI::create_objects 1\n");
264 // source = new VWindowSource(mwindow,
266 // mwindow->theme->vsource_x,
267 // mwindow->theme->vsource_y);
268 // source->create_objects();
269 update_sources(_("None"));
271 //printf("VWindowGUI::create_objects 2\n");
278 int VWindowGUI::resize_event(int w, int h)
280 mwindow->session->vwindow_x = get_x();
281 mwindow->session->vwindow_y = get_y();
282 mwindow->session->vwindow_w = w;
283 mwindow->session->vwindow_h = h;
285 mwindow->theme->get_vwindow_sizes(this);
286 mwindow->theme->draw_vwindow_bg(this);
289 //printf("VWindowGUI::resize_event %d %d\n", __LINE__, mwindow->theme->vedit_y);
290 edit_panel->reposition_buttons(mwindow->theme->vedit_x,
291 mwindow->theme->vedit_y);
293 timebar->resize_event();
294 transport->reposition_buttons(mwindow->theme->vtransport_x,
295 mwindow->theme->vtransport_y);
296 clock->reposition_window(mwindow->theme->vtime_x,
297 mwindow->theme->vtime_y,
298 mwindow->theme->vtime_w,
300 canvas->reposition_window(0,
301 mwindow->theme->vcanvas_x,
302 mwindow->theme->vcanvas_y,
303 mwindow->theme->vcanvas_w,
304 mwindow->theme->vcanvas_h);
305 //printf("VWindowGUI::resize_event %d %d\n", __LINE__, mwindow->theme->vcanvas_x);
306 // source->reposition_window(mwindow->theme->vsource_x,
307 // mwindow->theme->vsource_y);
308 meters->reposition_window(mwindow->theme->vmeter_x,
309 mwindow->theme->vmeter_y,
311 mwindow->theme->vmeter_h);
313 BC_WindowBase::resize_event(w, h);
321 int VWindowGUI::translation_event()
323 mwindow->session->vwindow_x = get_x();
324 mwindow->session->vwindow_y = get_y();
328 int VWindowGUI::close_event()
331 int i = mwindow->vwindows.size();
332 while( --i >= 0 && mwindow->vwindows.get(i)->gui != this );
338 mwindow->session->show_vwindow = 0;
341 mwindow->gui->lock_window("VWindowGUI::close_event");
342 mwindow->gui->mainmenu->show_vwindow->set_checked(0);
343 mwindow->gui->unlock_window();
345 lock_window("VWindowGUI::close_event");
346 mwindow->save_defaults();
350 int VWindowGUI::keypress_event()
353 switch( get_keypress() ) {
360 mwindow->undo_entry(this);
363 mwindow->redo_entry(this);
366 int on = canvas->get_fullscreen() ? 0 : 1;
367 canvas->set_fullscreen(on, 1);
370 canvas->set_fullscreen(0, 1);
376 if( ctrl_down() && shift_down() ) {
377 resend_event(mwindow->gui);
383 result = transport->keypress_event();
387 int VWindowGUI::button_press_event()
389 if( vwindow->get_edl() != 0 && canvas->get_canvas() &&
390 mwindow->edl->session->vwindow_click2play &&
391 canvas->get_canvas()->get_cursor_over_window() ) {
392 switch( get_buttonpress() ) {
394 if( !vwindow->playback_engine->is_playing_back ) {
395 double length = vwindow->get_edl()->tracks->total_playable_length();
396 double position = vwindow->playback_engine->get_tracking_position();
397 if( position >= length ) transport->goto_start();
399 return transport->forward_play->handle_event();
401 if( !vwindow->playback_engine->is_playing_back ) {
402 double position = vwindow->playback_engine->get_tracking_position();
403 if( position <= 0 ) transport->goto_end();
405 return transport->reverse_play->handle_event();
406 case RIGHT_BUTTON: // activates popup
409 return transport->frame_forward_play->handle_event();
411 return transport->frame_reverse_play->handle_event();
414 if(canvas->get_canvas())
415 return canvas->button_press_event_base(canvas->get_canvas());
419 int VWindowGUI::cursor_leave_event()
421 if(canvas->get_canvas())
422 return canvas->cursor_leave_event_base(canvas->get_canvas());
426 int VWindowGUI::cursor_enter_event()
428 if(canvas->get_canvas())
429 return canvas->cursor_enter_event_base(canvas->get_canvas());
433 int VWindowGUI::button_release_event()
435 if(canvas->get_canvas())
436 return canvas->button_release_event();
440 int VWindowGUI::cursor_motion_event()
442 if(canvas->get_canvas())
444 canvas->get_canvas()->unhide_cursor();
445 return canvas->cursor_motion_event();
451 void VWindowGUI::drag_motion()
454 if(get_hidden()) return;
455 if(mwindow->session->current_operation != DRAG_ASSET) return;
456 int need_highlight = cursor_above() && get_cursor_over_window() ? 1 : 0;
457 if( highlighted == need_highlight ) return;
458 highlighted = need_highlight;
462 int VWindowGUI::drag_stop()
464 if( get_hidden() ) return 0;
467 mwindow->session->current_operation == DRAG_ASSET ) {
472 Indexable *indexable =
473 mwindow->session->drag_assets->size() > 0 ?
474 (Indexable *)mwindow->session->drag_assets->get(0) :
475 mwindow->session->drag_clips->size() > 0 ?
476 (Indexable *)mwindow->session->drag_clips->get(0) : 0;
478 vwindow->change_source(indexable);
480 lock_window("VWindowGUI::drag_stop");
487 void VWindowGUI::stop_transport()
489 if( !transport->is_stopped() ) {
491 transport->handle_transport(STOP, 1);
492 lock_window("VWindowGUI::panel_stop_transport");
496 void VWindowGUI::update_meters()
498 if(mwindow->edl->session->vwindow_meter != meters->visible)
500 meters->set_meters(meters->meter_count,
501 mwindow->edl->session->vwindow_meter);
502 mwindow->theme->get_vwindow_sizes(this);
503 resize_event(get_w(), get_h());
509 VWindowMeters::VWindowMeters(MWindow *mwindow,
514 : MeterPanel(mwindow,
520 mwindow->edl->session->audio_channels,
521 mwindow->edl->session->vwindow_meter,
525 this->mwindow = mwindow;
529 VWindowMeters::~VWindowMeters()
533 int VWindowMeters::change_status_event(int new_status)
535 mwindow->edl->session->vwindow_meter = new_status;
536 gui->update_meters();
541 VWindowEditing::VWindowEditing(MWindow *mwindow, VWindow *vwindow)
542 : EditPanel(mwindow, vwindow->gui, VWINDOW_ID,
543 mwindow->theme->vedit_x, mwindow->theme->vedit_y,
545 0, // use_editing_mode
562 0) // use_gang_tracks
564 this->mwindow = mwindow;
565 this->vwindow = vwindow;
568 VWindowEditing::~VWindowEditing()
572 #define relock_vm(s) \
573 vwindow->gui->unlock_window(); \
574 mwindow->gui->lock_window("VWindowEditing::" s)
575 #define relock_mv(s) \
576 mwindow->gui->unlock_window(); \
577 vwindow->gui->lock_window("VWindowEditing::" s)
579 double VWindowEditing::get_position()
581 EDL *edl = vwindow->get_edl();
582 double position = !edl ? 0 : edl->local_session->get_selectionstart(1);
586 void VWindowEditing::set_position(double position)
588 EDL *edl = vwindow->get_edl();
590 if( get_position() != position ) {
591 if( position < 0 ) position = 0;
592 edl->local_session->set_selectionstart(position);
593 edl->local_session->set_selectionend(position);
594 vwindow->update_position();
598 void VWindowEditing::set_click_to_play(int v)
600 click2play->update(v);
601 relock_vm("set_click_to_play");
602 mwindow->edl->session->vwindow_click2play = v;
603 mwindow->update_vwindow();
604 relock_mv("set_click_to_play");
607 void VWindowEditing::panel_stop_transport()
609 vwindow->gui->stop_transport();
612 void VWindowEditing::panel_toggle_label()
614 if( !vwindow->get_edl() ) return;
615 EDL *edl = vwindow->get_edl();
616 edl->labels->toggle_label(edl->local_session->get_selectionstart(1),
617 edl->local_session->get_selectionend(1));
618 vwindow->gui->timebar->update(1);
621 void VWindowEditing::panel_next_label(int cut)
623 if( !vwindow->get_edl() ) return;
624 vwindow->interrupt_playback(1);
626 EDL *edl = vwindow->get_edl();
627 Label *current = edl->labels->next_label(
628 edl->local_session->get_selectionstart(1));
629 double position = current ? current->position :
630 edl->tracks->total_length();
631 edl->local_session->set_selectionstart(position);
632 edl->local_session->set_selectionend(position);
633 vwindow->update_position();
634 vwindow->gui->timebar->update(1);
637 void VWindowEditing::panel_prev_label(int cut)
639 if( !vwindow->get_edl() ) return;
640 vwindow->interrupt_playback(1);
642 EDL *edl = vwindow->get_edl();
643 Label *current = edl->labels->prev_label(
644 edl->local_session->get_selectionstart(1));
645 double position = !current ? 0 : current->position;
646 edl->local_session->set_selectionstart(position);
647 edl->local_session->set_selectionend(position);
648 vwindow->update_position();
649 vwindow->gui->timebar->update(1);
652 void VWindowEditing::panel_prev_edit(int cut) {} // not used
653 void VWindowEditing::panel_next_edit(int cut) {} // not used
655 void VWindowEditing::panel_copy_selection()
657 vwindow->copy(vwindow->gui->shift_down());
660 void VWindowEditing::panel_overwrite_selection()
662 if( !vwindow->get_edl() ) return;
663 relock_vm("overwrite_selection");
664 mwindow->overwrite(vwindow->get_edl(), vwindow->gui->shift_down());
665 relock_mv("overwrite_selection");
668 void VWindowEditing::panel_splice_selection()
670 if( !vwindow->get_edl() ) return;
671 relock_vm("splice_selection");
672 mwindow->splice(vwindow->get_edl(), vwindow->gui->shift_down());
673 relock_mv("splice_selection");
676 void VWindowEditing::panel_set_inpoint()
678 vwindow->set_inpoint();
681 void VWindowEditing::panel_set_outpoint()
683 vwindow->set_outpoint();
686 void VWindowEditing::panel_unset_inoutpoint()
688 vwindow->unset_inoutpoint();
691 void VWindowEditing::panel_to_clip()
693 EDL *edl = vwindow->get_edl();
695 mwindow->to_clip(edl, _("viewer window: "), subwindow->shift_down());
699 void VWindowEditing::panel_cut() {}
700 void VWindowEditing::panel_paste() {}
701 void VWindowEditing::panel_fit_selection() {}
702 void VWindowEditing::panel_fit_autos(int all) {}
703 void VWindowEditing::panel_set_editing_mode(int mode) {}
704 void VWindowEditing::panel_set_auto_keyframes(int v) {}
705 void VWindowEditing::panel_set_span_keyframes(int v) {}
706 void VWindowEditing::panel_set_labels_follow_edits(int v) {}
707 void VWindowEditing::panel_set_gang_tracks(int v) {}
710 VWindowSource::VWindowSource(MWindow *mwindow, VWindowGUI *vwindow, int x, int y)
711 : BC_PopupTextBox(vwindow, &vwindow->sources, "",
712 x, y, xS(200), yS(200))
714 this->mwindow = mwindow;
715 this->vwindow = vwindow;
718 VWindowSource::~VWindowSource()
722 int VWindowSource::handle_event()
728 VWindowTransport::VWindowTransport(MWindow *mwindow,
732 : PlayTransport(mwindow,
740 EDL* VWindowTransport::get_edl()
742 return gui->vwindow->get_edl();
746 void VWindowTransport::goto_start()
748 gui->unlock_window();
749 handle_transport(REWIND, 1);
750 gui->lock_window("VWindowTransport::goto_start");
751 gui->vwindow->goto_start();
754 void VWindowTransport::goto_end()
756 gui->unlock_window();
757 handle_transport(GOTO_END, 1);
758 gui->lock_window("VWindowTransport::goto_end");
759 gui->vwindow->goto_end();
765 VWindowCanvas::VWindowCanvas(MWindow *mwindow, VWindowGUI *gui)
768 mwindow->theme->vcanvas_x,
769 mwindow->theme->vcanvas_y,
770 mwindow->theme->vcanvas_w,
771 mwindow->theme->vcanvas_h,
774 //printf("VWindowCanvas::VWindowCanvas %d %d\n", __LINE__, mwindow->theme->vcanvas_x);
775 this->mwindow = mwindow;
779 void VWindowCanvas::create_objects(EDL *edl)
781 Canvas::create_objects(edl);
782 canvas_menu->add_item(new CanvasPopupRemoveSource(this));
785 void VWindowCanvas::zoom_resize_window(float percentage)
787 EDL *edl = gui->vwindow->get_edl();
788 if(!edl) edl = mwindow->edl;
790 int canvas_w, canvas_h;
793 // Get required canvas size
794 calculate_sizes(edl->get_aspect_ratio(),
795 edl->session->output_w,
796 edl->session->output_h,
801 // Estimate window size from current borders
802 new_w = canvas_w + (gui->get_w() - mwindow->theme->vcanvas_w);
803 new_h = canvas_h + (gui->get_h() - mwindow->theme->vcanvas_h);
805 mwindow->session->vwindow_w = new_w;
806 mwindow->session->vwindow_h = new_h;
808 mwindow->theme->get_vwindow_sizes(gui);
810 // Estimate again from new borders
811 new_w = canvas_w + (mwindow->session->vwindow_w - mwindow->theme->vcanvas_w);
812 new_h = canvas_h + (mwindow->session->vwindow_h - mwindow->theme->vcanvas_h);
815 gui->resize_window(new_w, new_h);
816 gui->resize_event(new_w, new_h);
819 void VWindowCanvas::zoom_auto()
821 EDL *edl = gui->vwindow->get_edl();
822 if(!edl) edl = mwindow->edl;
826 void VWindowCanvas::close_source()
828 gui->vwindow->interrupt_playback(1);
829 gui->vwindow->delete_source(1, 1);
832 int VWindowCanvas::scope_on()
834 EditPanelScopeDialog *scope_dialog = gui->edit_panel->scope_dialog;
835 if( !scope_dialog || !scope_dialog->scope_gui ) return 0;
836 if( scope_dialog->scope_gui->use_refresh ) return 0;
837 if( scope_dialog->scope_gui->use_release ) return 0;
838 return scope_dialog->running();
841 void VWindowCanvas::draw_scope(VFrame *output, int refresh)
843 if( !output ) return;
844 EditPanelScopeDialog *scope_dialog = gui->edit_panel->scope_dialog;
845 if( !scope_dialog || !scope_dialog->scope_gui ) return;
846 if( scope_dialog->scope_gui->use_refresh && !refresh ) return;
847 if( scope_dialog->scope_gui->use_release && refresh >= 0 ) return;
848 scope_dialog->process(output);
851 int VWindowCanvas::button_release_event()
853 BC_WindowBase *window = get_canvas();
854 if( window && !window->get_video_on() )
855 draw_scope(refresh_frame, -1);
856 return Canvas::button_release_event();
859 void VWindowCanvas::draw_refresh(int flush)
861 if( !get_canvas()->get_video_on() ) {
862 int cw = get_canvas()->get_w(), ch = get_canvas()->get_h();
863 get_canvas()->clear_box(0, 0, cw, ch);
865 EDL *edl = gui->vwindow->get_edl();
866 if( refresh_frame && edl ) {
867 int ow = get_output_w(edl), oh = get_output_h(edl);
868 if( ow > 0 && oh > 0 ) {
869 float in_x1, in_y1, in_x2, in_y2;
870 float out_x1, out_y1, out_x2, out_y2;
872 in_x1, in_y1, in_x2, in_y2,
873 out_x1, out_y1, out_x2, out_y2);
874 // input scaled from session to refresh frame coordinates
875 int rw = refresh_frame->get_w();
876 int rh = refresh_frame->get_h();
877 float xs = (float)rw / ow;
878 float ys = (float)rh / oh;
879 in_x1 *= xs; in_x2 *= xs;
880 in_y1 *= ys; in_y2 *= ys;
881 get_canvas()->draw_vframe(refresh_frame,
882 (int)out_x1, (int)out_y1,
883 (int)(out_x2 - out_x1), (int)(out_y2 - out_y1),
884 (int)in_x1, (int)in_y1,
885 (int)(in_x2 - in_x1), (int)(in_y2 - in_y1),
889 if( !get_canvas()->get_video_on() ) {
891 get_canvas()->flash(flush);
895 int VWindowCanvas::need_overlays()
897 if( gui->highlighted ) return 1;
901 void VWindowCanvas::draw_overlays()
903 if( gui->highlighted )
905 get_canvas()->set_color(WHITE);
906 get_canvas()->set_inverse();
907 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
908 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
909 get_canvas()->set_opaque();