Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / editpanel.C
index 6488be94564e9334529dd4e365307f4977e58278..6da2d0da5b1be51be9109b47a9782b8e1ebfd0ef 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * CINELERRA
  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2003-2016 Cinelerra CV contributors
  *
  * 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
@@ -75,7 +76,9 @@ EditPanel::EditPanel(MWindow *mwindow,
        int use_commercial,
        int use_goto,
        int use_clk2play,
-       int use_scope)
+       int use_scope,
+       int use_gang_tracks,
+       int use_timecode)
 {
        this->window_id = window_id;
        this->editing_mode = editing_mode;
@@ -98,6 +101,8 @@ EditPanel::EditPanel(MWindow *mwindow,
        this->use_goto = use_goto;
        this->use_clk2play = use_clk2play;
        this->use_scope = use_scope;
+       this->use_gang_tracks = use_gang_tracks;
+       this->use_timecode = use_timecode;
 
        this->x = x;
        this->y = y;
@@ -117,6 +122,7 @@ EditPanel::EditPanel(MWindow *mwindow,
        this->nextlabel = 0;
        this->prevedit = 0;
        this->nextedit = 0;
+       this->gang_tracks = 0;
        this->undo = 0;
        this->redo = 0;
        this->meter_panel = 0;
@@ -157,6 +163,7 @@ void EditPanel::update()
                        mwindow->edl->session->vwindow_click2play ;
                click2play->set_value(value);
        }
+       if( gang_tracks ) gang_tracks->update(mwindow->edl->local_session->gang_tracks);
        if( meters ) {
                if( is_cwindow() ) {
                        meters->update(mwindow->edl->session->cwindow_meter);
@@ -171,7 +178,7 @@ void EditPanel::update()
 
 int EditPanel::calculate_w(MWindow *mwindow, int use_keyframe, int total_buttons)
 {
-       int button_w = mwindow->theme->get_image_set("meters")[0]->get_w();
+       int button_w = xS(24); // mwindow->theme->get_image_set("meters")[0]->get_w();
        int result = button_w * total_buttons;
        if( use_keyframe )
                result += 2*(button_w + mwindow->theme->toggle_margin);
@@ -259,16 +266,6 @@ void EditPanel::create_buttons()
                x1 += paste->get_w();
        }
 
-       if( use_meters ) {
-               if( meter_panel ) {
-                       meters = new MeterShow(mwindow, meter_panel, x1, y1);
-                       subwindow->add_subwindow(meters);
-                       x1 += meters->get_w();
-               }
-               else
-                       printf("EditPanel::create_objects: meter_panel == 0\n");
-       }
-
        if( use_labels ) {
                labelbutton = new EditLabelbutton(mwindow, this, x1, y1);
                subwindow->add_subwindow(labelbutton);
@@ -328,6 +325,28 @@ void EditPanel::create_buttons()
                scope_dialog = new EditPanelScopeDialog(mwindow, this);
        }
 
+       if( use_timecode ) {
+               timecode = new EditPanelTimecode(mwindow, this, x1, y1);
+               subwindow->add_subwindow(timecode);
+               x1 += timecode->get_w();
+       }
+
+       if( use_gang_tracks ) {
+               gang_tracks = new EditPanelGangTracks(mwindow, this, x1, y1-yS(1));
+               subwindow->add_subwindow(gang_tracks);
+               x1 += gang_tracks->get_w();
+       }
+
+       if( use_meters ) {
+               if( meter_panel ) {
+                       meters = new MeterShow(mwindow, meter_panel, x1, y1);
+                       subwindow->add_subwindow(meters);
+                       x1 += meters->get_w();
+               }
+               else
+                       printf("EditPanel::create_objects: meter_panel == 0\n");
+       }
+
        if( use_commercial ) {
                commercial = new EditCommercial(mwindow, this, x1, y1);
                subwindow->add_subwindow(commercial);
@@ -393,11 +412,6 @@ void EditPanel::reposition_buttons(int x, int y)
                x1 += paste->get_w();
        }
 
-       if( use_meters ) {
-               meters->reposition_window(x1, y1);
-               x1 += meters->get_w();
-       }
-
        if( use_labels ) {
                labelbutton->reposition_window(x1, y1);
                x1 += labelbutton->get_w();
@@ -443,6 +457,15 @@ void EditPanel::reposition_buttons(int x, int y)
                scope->reposition_window(x1, y1-yS(1));
                x1 += scope->get_w();
        }
+       if( use_timecode ) {
+               timecode->reposition_window(x1, y1);
+               x1 += timecode->get_w();
+       }
+
+       if( use_meters ) {
+               meters->reposition_window(x1, y1);
+               x1 += meters->get_w();
+       }
 }
 
 void EditPanel::create_objects()
@@ -462,6 +485,8 @@ EditLabelbutton::EditLabelbutton(MWindow *mwindow, EditPanel *panel, int x, int
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Toggle label at current position ( l )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Labels");
 }
 
 EditLabelbutton::~EditLabelbutton()
@@ -471,7 +496,7 @@ int EditLabelbutton::keypress_event()
 {
        if( get_keypress() == 'l' && !alt_down() )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 int EditLabelbutton::handle_event()
 {
@@ -487,6 +512,8 @@ EditNextLabel::EditNextLabel(MWindow *mwindow,
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Next label ( ctrl -> )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Labels");
 }
 EditNextLabel::~EditNextLabel()
 {
@@ -504,7 +531,7 @@ int EditNextLabel::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditNextLabel::handle_event()
 {
@@ -521,6 +548,8 @@ EditPrevLabel::EditPrevLabel(MWindow *mwindow,
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Previous label ( ctrl <- )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Labels");
 }
 EditPrevLabel::~EditPrevLabel()
 {
@@ -538,7 +567,7 @@ int EditPrevLabel::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditPrevLabel::handle_event()
 {
@@ -555,6 +584,8 @@ EditPrevEdit::EditPrevEdit(MWindow *mwindow,
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Previous edit (alt <- )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Snapping while Cutting and Dragging");
 }
 EditPrevEdit::~EditPrevEdit()
 {
@@ -572,7 +603,7 @@ int EditPrevEdit::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditPrevEdit::handle_event()
 {
@@ -589,6 +620,8 @@ EditNextEdit::EditNextEdit(MWindow *mwindow,
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Next edit ( alt -> )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Snapping while Cutting and Dragging");
 }
 EditNextEdit::~EditNextEdit()
 {
@@ -606,7 +639,7 @@ int EditNextEdit::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditNextEdit::handle_event()
 {
@@ -622,6 +655,8 @@ EditCopy::EditCopy(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Copy ( c )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Cut and Paste Editing");
 }
 EditCopy::~EditCopy()
 {
@@ -629,12 +664,12 @@ EditCopy::~EditCopy()
 
 int EditCopy::keypress_event()
 {
-       if( alt_down() ) return 0;
+       if( alt_down() ) return context_help_check_and_show();
        if( (get_keypress() == 'c' && !ctrl_down()) ||
            (panel->is_vwindow() && get_keypress() == 'C') ) {
                return handle_event();
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditCopy::handle_event()
 {
@@ -649,6 +684,8 @@ EditOverwrite::EditOverwrite(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Overwrite ( b )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Two Screen Editing");
 }
 EditOverwrite::~EditOverwrite()
 {
@@ -660,13 +697,13 @@ int EditOverwrite::handle_event()
 }
 int EditOverwrite::keypress_event()
 {
-       if( alt_down() ) return 0;
+       if( alt_down() ) return context_help_check_and_show();
        if( get_keypress() == 'b' ||
            (panel->is_vwindow() && get_keypress() == 'B') ) {
                handle_event();
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //set_inpoint
@@ -677,6 +714,8 @@ EditInPoint::EditInPoint(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("In point ( [ or < )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("In\\/Out Points");
 }
 EditInPoint::~EditInPoint()
 {
@@ -701,7 +740,7 @@ int EditInPoint::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //set_outpoint
@@ -712,6 +751,8 @@ EditOutPoint::EditOutPoint(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Out point ( ] or > )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("In\\/Out Points");
 }
 EditOutPoint::~EditOutPoint()
 {
@@ -736,7 +777,7 @@ int EditOutPoint::keypress_event()
                        return 1;
                }
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //splice_selection
@@ -746,6 +787,8 @@ EditSplice::EditSplice(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Splice ( v )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Two Screen Editing");
 }
 EditSplice::~EditSplice()
 {
@@ -757,13 +800,13 @@ int EditSplice::handle_event()
 }
 int EditSplice::keypress_event()
 {
-       if( alt_down() ) return 0;
+       if( alt_down() ) return context_help_check_and_show();
        if( (get_keypress() == 'v' && !ctrl_down()) ||
            (panel->is_vwindow() && get_keypress() == 'V') ) {
                handle_event();
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //to_clip
@@ -773,6 +816,8 @@ EditToClip::EditToClip(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("To clip ( i )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Two Screen Editing");
 }
 EditToClip::~EditToClip()
 {
@@ -785,13 +830,13 @@ int EditToClip::handle_event()
 
 int EditToClip::keypress_event()
 {
-       if( alt_down() ) return 0;
+       if( alt_down() ) return context_help_check_and_show();
        if( get_keypress() == 'i' ||
            (panel->is_vwindow() && get_keypress() == 'I') ) {
                handle_event();
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //cut
@@ -801,6 +846,8 @@ EditCut::EditCut(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Split | Cut ( x )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Cut and Paste Editing");
 }
 EditCut::~EditCut()
 {
@@ -808,10 +855,10 @@ EditCut::~EditCut()
 int EditCut::keypress_event()
 {
        if( ctrl_down() || shift_down() || alt_down() )
-               return 0;
+               return context_help_check_and_show();
        if( get_keypress() == 'x' )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 
 int EditCut::handle_event()
@@ -827,6 +874,8 @@ EditPaste::EditPaste(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Paste ( v )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Cut and Paste Editing");
 }
 EditPaste::~EditPaste()
 {
@@ -836,7 +885,7 @@ int EditPaste::keypress_event()
 {
        if( get_keypress() == 'v' && !ctrl_down() )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 int EditPaste::handle_event()
 {
@@ -851,6 +900,8 @@ EditFit::EditFit(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Fit selection to display ( f )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Transport and Buttons Bar");
 }
 EditFit::~EditFit()
 {
@@ -861,7 +912,7 @@ int EditFit::keypress_event()
                handle_event();
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditFit::handle_event()
 {
@@ -876,6 +927,8 @@ EditFitAutos::EditFitAutos(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Fit all autos to display ( Alt + f )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Using Autos");
 }
 EditFitAutos::~EditFitAutos()
 {
@@ -886,7 +939,7 @@ int EditFitAutos::keypress_event()
                panel->panel_fit_autos(!ctrl_down() ? 1 : 0);
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 int EditFitAutos::handle_event()
 {
@@ -904,6 +957,8 @@ ArrowButton::ArrowButton(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Drag and drop editing mode"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Drag and Drop Editing");
 }
 
 int ArrowButton::handle_event()
@@ -924,6 +979,8 @@ IBeamButton::IBeamButton(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Cut and paste editing mode"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Cut and Paste Editing");
 }
 
 int IBeamButton::handle_event()
@@ -945,6 +1002,8 @@ KeyFrameButton::KeyFrameButton(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Generate keyframes while tweeking (j)"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Generate Keyframes while Tweaking");
 }
 
 int KeyFrameButton::handle_event()
@@ -962,7 +1021,7 @@ int KeyFrameButton::keypress_event()
                panel->panel_set_auto_keyframes(value);
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 //set_span_keyframes
@@ -975,6 +1034,8 @@ SpanKeyFrameButton::SpanKeyFrameButton(MWindow *mwindow, EditPanel *panel, int x
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Allow keyframe spanning"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Allow Keyframe Spanning");
 }
 
 int SpanKeyFrameButton::handle_event()
@@ -993,6 +1054,8 @@ LockLabelsButton::LockLabelsButton(MWindow *mwindow, EditPanel *panel, int x, in
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Lock labels from moving with edits"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Labels");
 }
 
 int LockLabelsButton::handle_event()
@@ -1010,6 +1073,8 @@ EditManualGoto::EditManualGoto(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->panel = panel;
        mangoto = new ManualGoto(mwindow, panel);
        set_tooltip(_("Manual goto ( g )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Transport and Buttons Bar");
 }
 EditManualGoto::~EditManualGoto()
 {
@@ -1027,7 +1092,7 @@ int EditManualGoto::keypress_event()
                handle_event();
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 
@@ -1040,6 +1105,8 @@ EditClick2Play::EditClick2Play(MWindow *mwindow, EditPanel *panel, int x, int y)
         this->mwindow = mwindow;
         this->panel = panel;
         set_tooltip(_("Click to play (p)"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Click to Play in Viewer and Compositor");
 }
 int EditClick2Play::handle_event()
 {
@@ -1056,7 +1123,7 @@ int EditClick2Play::keypress_event()
                panel->set_click_to_play(value);
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 
@@ -1066,6 +1133,8 @@ EditCommercial::EditCommercial(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Commercial ( shift A )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("The commercial DB");
 }
 EditCommercial::~EditCommercial()
 {
@@ -1073,10 +1142,10 @@ EditCommercial::~EditCommercial()
 int EditCommercial::keypress_event()
 {
        if( ctrl_down() || !shift_down() || alt_down() )
-               return 0;
+               return context_help_check_and_show();
        if( get_keypress() == 'A' )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 
 int EditCommercial::handle_event()
@@ -1105,7 +1174,9 @@ EditUndo::EditUndo(MWindow *mwindow, EditPanel *panel, int x, int y)
 {
        this->mwindow = mwindow;
        this->panel = panel;
-       set_tooltip(_("Undo ( z )"));
+       set_tooltip(_("Undo ( z or Ctrl-z)"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Transport and Buttons Bar");
 }
 EditUndo::~EditUndo()
 {
@@ -1113,10 +1184,10 @@ EditUndo::~EditUndo()
 int EditUndo::keypress_event()
 {
        if( ctrl_down() || shift_down() || alt_down() )
-               return 0;
+               return context_help_check_and_show();
        if( get_keypress() == 'z' )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 int EditUndo::handle_event()
 {
@@ -1130,6 +1201,8 @@ EditRedo::EditRedo(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("Redo ( shift Z )"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Transport and Buttons Bar");
 }
 EditRedo::~EditRedo()
 {
@@ -1137,10 +1210,10 @@ EditRedo::~EditRedo()
 int EditRedo::keypress_event()
 {
        if( ctrl_down() || !shift_down() || alt_down() )
-               return 0;
+               return context_help_check_and_show();
        if( get_keypress() == 'Z' )
                return handle_event();
-       return 0;
+       return context_help_check_and_show();
 }
 int EditRedo::handle_event()
 {
@@ -1224,6 +1297,9 @@ void EditPanelScopeGUI::create_objects()
        use_wave_gain = session->use_wave_gain;
        use_vect_gain = session->use_vect_gain;
        use_smooth = session->use_smooth;
+       use_refresh = session->use_refresh;
+       use_release = session->use_release;
+       use_graticule = session->use_graticule;
        ScopeGUI::create_objects();
 }
 
@@ -1238,6 +1314,9 @@ void EditPanelScopeGUI::toggle_event()
        session->use_wave_gain = use_wave_gain;
        session->use_vect_gain = use_vect_gain;
        session->use_smooth = use_smooth;
+       session->use_refresh = use_refresh;
+       session->use_release = use_release;
+       session->use_graticule = use_graticule;
 }
 
 int EditPanelScopeGUI::translation_event()
@@ -1265,6 +1344,8 @@ EditPanelScope::EditPanelScope(MWindow *mwindow, EditPanel *panel, int x, int y)
        this->mwindow = mwindow;
        this->panel = panel;
        set_tooltip(_("View scope"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Videoscope");
 }
 
 EditPanelScope::~EditPanelScope()
@@ -1298,3 +1379,258 @@ int EditPanelScope::handle_event()
        return 1;
 }
 
+const char *EditPanelGangTracks::gang_tips[TOTAL_GANGS] = {
+       N_("Currently: Gang None\n  Click to: Gang Channels"),
+       N_("Currently: Gang Channels\n  Click to: Gang Media"),
+       N_("Currently: Gang Media\n  Click to: Gang None"),
+};
+
+EditPanelGangTracks::EditPanelGangTracks(MWindow *mwindow, EditPanel *panel,
+               int x, int y)
+ : BC_Button(x, y, get_images(mwindow))
+{
+       this->mwindow = mwindow;
+       this->panel = panel;
+       int gang = mwindow->edl->local_session->gang_tracks;
+       set_tooltip(_(gang_tips[gang]));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Displaying tracks: Ganged mode");
+}
+
+EditPanelGangTracks::~EditPanelGangTracks()
+{
+}
+
+VFrame **EditPanelGangTracks::gang_images[TOTAL_GANGS];
+
+VFrame **EditPanelGangTracks::get_images(MWindow *mwindow)
+{
+       gang_images[GANG_NONE] = mwindow->theme->get_image_set("gang0");
+       gang_images[GANG_MEDIA] = mwindow->theme->get_image_set("gang1");
+       gang_images[GANG_CHANNELS] = mwindow->theme->get_image_set("gang2");
+       int gang = mwindow->edl->local_session->gang_tracks;
+       return gang_images[gang];
+}
+
+void EditPanelGangTracks::update(int gang)
+{
+       set_images(gang_images[gang]);
+       draw_face();
+       set_tooltip(_(gang_tips[gang]));
+}
+
+int EditPanelGangTracks::handle_event()
+{
+       int gang = mwindow->edl->local_session->gang_tracks;
+       if( !shift_down() ) {
+               if( ++gang > GANG_MEDIA ) gang = GANG_NONE;
+       }
+       else {
+               if( --gang < GANG_NONE ) gang = GANG_MEDIA;
+       }
+       update(gang);
+       panel->panel_set_gang_tracks(gang);
+       return 1;
+}
+
+
+EditPanelTimecode::EditPanelTimecode(MWindow *mwindow,
+       EditPanel *panel, int x, int y)
+ : BC_Button(x, y, mwindow->theme->get_image_set("clapperbutton"))
+{
+       this->mwindow = mwindow;
+       this->panel = panel;
+       tc_dialog = 0;
+       set_tooltip(_("Set Timecode"));
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Align Timecodes");
+}
+
+EditPanelTimecode::~EditPanelTimecode()
+{
+       delete tc_dialog;
+}
+
+int EditPanelTimecode::handle_event()
+{
+       if( !tc_dialog )
+               tc_dialog = new EditPanelTcDialog(mwindow, panel);
+       int px, py;
+       get_pop_cursor(px, py, 0);
+       tc_dialog->start_dialog(px, py);
+       return 1;
+}
+
+EditPanelTcDialog::EditPanelTcDialog(MWindow *mwindow, EditPanel *panel)
+ : BC_DialogThread()
+{
+       this->mwindow = mwindow;
+       this->panel = panel;
+       tc_gui = 0;
+       px = py = 0;
+}
+
+EditPanelTcDialog::~EditPanelTcDialog()
+{
+       close_window();
+}
+
+#define TCW_W xS(200)
+#define TCW_H yS(120)
+
+void EditPanelTcDialog::start_dialog(int px, int py)
+{
+       this->px = px - TCW_W/2;
+       this->py = py - TCW_H/2;
+       start();
+}
+
+BC_Window *EditPanelTcDialog::new_gui()
+{
+       tc_gui = new EditPanelTcWindow(this, px, py);
+       tc_gui->create_objects();
+       double timecode = mwindow->get_timecode_offset();
+       tc_gui->update(timecode);
+       tc_gui->show_window();
+       return tc_gui;
+}
+
+void EditPanelTcDialog::handle_done_event(int result)
+{
+       if( result ) return;
+       double ofs = tc_gui->get_timecode();
+       mwindow->set_timecode_offset(ofs);
+}
+
+EditPanelTcWindow::EditPanelTcWindow(EditPanelTcDialog *tc_dialog, int x, int y)
+ : BC_Window(_(PROGRAM_NAME ": Timecode"), x, y,
+       TCW_W, TCW_H, TCW_W, TCW_H, 0, 0, 1)
+{
+       this->tc_dialog = tc_dialog;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Align Timecodes");
+}
+
+EditPanelTcWindow::~EditPanelTcWindow()
+{
+}
+
+double EditPanelTcWindow::get_timecode()
+{
+       int hrs = atoi(hours->get_text());
+       int mins = atoi(minutes->get_text());
+       int secs = atoi(seconds->get_text());
+       int frms = atoi(frames->get_text());
+       double frame_rate = tc_dialog->mwindow->edl->session->frame_rate;
+       double timecode = hrs*3600 + mins*60 + secs + frms/frame_rate;
+       return timecode;
+}
+
+void EditPanelTcWindow::update(double timecode)
+{
+       if( timecode < 0 ) timecode = 0;
+       int64_t pos = timecode;
+       int hrs = pos/3600;
+       int mins = pos/60 - hrs*60;
+       int secs = pos - hrs*3600 - mins*60;
+       double frame_rate = tc_dialog->mwindow->edl->session->frame_rate;
+       int frms = (timecode-pos) * frame_rate;
+       hours->update(hrs);
+       minutes->update(mins);
+       seconds->update(secs);
+       frames->update(frms);
+}
+
+void EditPanelTcWindow::create_objects()
+{
+       lock_window("EditPanelTcWindow::create_objects");
+       int x = xS(20), y = yS(5);
+       BC_Title *title = new BC_Title(x - 2, y, _("hour  min   sec   frms"), SMALLFONT);
+       add_subwindow(title);  y += title->get_h() + xS(3);
+       hours = new EditPanelTcInt(this, x, y, xS(26), 99, "%02i");
+       add_subwindow(hours);    x += hours->get_w() + xS(4);
+       minutes = new EditPanelTcInt(this, x, y, xS(26), 59, "%02i");
+       add_subwindow(minutes);  x += minutes->get_w() + xS(4);
+       seconds = new EditPanelTcInt(this, x, y, xS(26), 60, "%02i");
+       add_subwindow(seconds);  x += seconds->get_w() + xS(4);
+       frames = new EditPanelTcInt(this, x, y, xS(34), 999, "%03i");
+       add_subwindow(frames);   x += frames->get_w() + xS(16);
+       add_subwindow(new EditPanelTcReset(this, x, y));
+       double timecode = tc_dialog->mwindow->get_timecode_offset();
+       update(timecode);
+       add_subwindow(new BC_OKButton(this));
+       add_subwindow(new BC_CancelButton(this));
+       unlock_window();
+}
+
+EditPanelTcReset::EditPanelTcReset(EditPanelTcWindow *window, int x, int y)
+ : BC_Button(x, y, window->tc_dialog->mwindow->theme->get_image_set("reset_button"))
+{
+       this->window = window;
+}
+
+int EditPanelTcReset::handle_event()
+{
+       window->update(0);
+       return 1;
+}
+
+
+EditPanelTcInt::EditPanelTcInt(EditPanelTcWindow *window, int x, int y, int w,
+       int max, const char *format)
+ : BC_TextBox(x, y, w, 1, "")
+{
+       this->window = window;
+       this->max = max;
+       this->format = format;
+       digits = 1;
+       for( int m=max; (m/=10)>0; ++digits );
+}
+
+EditPanelTcInt::~EditPanelTcInt()
+{
+}
+
+int EditPanelTcInt::handle_event()
+{
+       int v = atoi(get_text());
+       if( v > max ) {
+               v = v % (max+1);
+               char string[BCSTRLEN];
+               sprintf(string, format, v);
+               BC_TextBox::update(string);
+       }
+       return 1;
+}
+
+void EditPanelTcInt::update(int v)
+{
+       char text[BCTEXTLEN];
+       if( v > max ) v = max;
+       sprintf(text, format, v);
+       BC_TextBox::update(text);
+}
+
+int EditPanelTcInt::keypress_event()
+{
+       if( get_keypress() == 'h' && alt_down() ) {
+               context_help_show("Align Timecodes");
+               return 1;
+       }
+
+       if( (int)strlen(get_text()) >= digits )
+               BC_TextBox::update("");
+       int key = get_keypress();
+       switch( key ) {
+       case TAB:   case LEFTTAB:
+       case LEFT:  case RIGHT:
+       case HOME:  case END:
+       case BACKSPACE:
+       case DELETE:
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+               return BC_TextBox::keypress_event();
+       }
+       return 1;
+}
+