Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / swindow.C
index 1604d8dbf371804fb36e6d1f938a256abc940e49..18f6abaaf3dfe79f5c28f8278a12fa2d67d18e1d 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2016-2020 William Morrow
+ *
+ * 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 "bchash.h"
 #include "bctimer.h"
@@ -48,7 +67,7 @@ int SWindowOK::button_press_event()
 
 int SWindowOK::keypress_event()
 {
-       return 0;
+       return context_help_check_and_show();
 }
 
 
@@ -73,7 +92,7 @@ int SWindowCancel::button_press_event()
 
 
 SWindowLoadPath::SWindowLoadPath(SWindowGUI *gui, int x, int y, char *path)
- : BC_TextBox(x, y, 200, 1, path)
+ : BC_TextBox(x, y, xS(200), 1, path)
 {
        this->sw_gui = gui;
 }
@@ -129,7 +148,7 @@ int SWindowSaveFile::handle_event()
                sw_gui->save_spumux_data();
        }
        else {
-               eprintf(_("script microdvd file path required"));
+               eprintf(_("script file path required"));
        }
        return 1;
 }
@@ -140,58 +159,61 @@ int SWindowSaveFile::handle_event()
 void SWindowGUI::create_objects()
 {
        lock_window("SWindowGUI::create_objects");
-       int x = 10, y = 10;
+       int x = xS(10), y = yS(10);
        BC_Title *title = new BC_Title(x, y, _("Path:"));
        add_subwindow(title);
-       int x1 = x + title->get_w() + pad, y1 = y;
+       int x1 = x + title->get_w() + xpad, y1 = y;
        load_path = new SWindowLoadPath(this, x1, y1, script_path);
        add_subwindow(load_path);
-       x1 += load_path->get_w() + 2*pad;
+       x1 += load_path->get_w() + 2*xpad;
        add_subwindow(load_file = new SWindowLoadFile(this, x1, y1));
-       x1 += load_file->get_w() + 2*pad;
+       x1 += load_file->get_w() + 2*xpad;
        add_subwindow(save_file = new SWindowSaveFile(this, x1, y1));
-       y += max(load_path->get_h(), load_file->get_h()) + pad;
-       x1 = x + pad, y1 = y;
+       x1 += save_file->get_w() + 2*xpad;
+       add_subwindow(save_format = new SWindowSaveFormat(this, x1, y1));
+       save_format->create_objects();
+       y += max(load_path->get_h(), load_file->get_h()) + ypad;
+       x1 = x + ypad, y1 = y;
        BC_Title *title1, *title2;
        add_subwindow(title1 = new BC_Title(x1, y1, _("File Size:")));
-       y += title1->get_h() + pad;
+       y += title1->get_h() + ypad;
        int y2 = y;
        add_subwindow(title2 = new BC_Title(x1, y2, _("Entries:")));
-       int x2 = x1 + max(title1->get_w(), title2->get_w()) + pad;
+       int x2 = x1 + max(title1->get_w(), title2->get_w()) + xpad;
        add_subwindow(script_filesz = new BC_Title(x2, y1, "0", MEDIUMFONT, YELLOW));
        add_subwindow(script_entries = new BC_Title(x2, y2, "0", MEDIUMFONT, YELLOW));
-       int x3 = x2 + max(script_entries->get_w()*8, script_filesz->get_w()*8) + pad;
+       int x3 = x2 + max(script_entries->get_w()*8, script_filesz->get_w()*8) + xpad;
        add_subwindow(title1 = new BC_Title(x3, y1, _("Lines:")));
        add_subwindow(title2 = new BC_Title(x3, y2, _("Texts:")));
-       int x4 = x3 + max(title1->get_w(), title2->get_w()) + pad;
+       int x4 = x3 + max(title1->get_w(), title2->get_w()) + xpad;
        add_subwindow(script_lines = new BC_Title(x4, y1, "0", MEDIUMFONT, YELLOW));
        add_subwindow(script_texts = new BC_Title(x4, y2, "0", MEDIUMFONT, YELLOW));
-       int x5 = x4 + max(script_lines->get_w()*8, script_texts->get_w()*8) + 2*pad;
+       int x5 = x4 + max(script_lines->get_w()*8, script_texts->get_w()*8) + 2*xpad;
        add_subwindow(prev_script = new ScriptPrev(this, x5, y1));
        add_subwindow(next_script = new ScriptNext(this, x5, y2));
-       int x6 = x5 + max(prev_script->get_w(), next_script->get_w()) + 2*pad;
+       int x6 = x5 + max(prev_script->get_w(), next_script->get_w()) + 2*xpad;
        add_subwindow(paste_script = new ScriptPaste(this, x6, y1));
        add_subwindow(clear_script = new ScriptClear(this, x6, y2));
-       y += max(title1->get_h(), title2->get_h()) + 2*pad;
+       y += max(title1->get_h(), title2->get_h()) + 2*ypad;
 
-       script_position = new ScriptPosition(this, x, y, 100);
+       script_position = new ScriptPosition(this, x, y, xS(100));
        script_position->create_objects();
-       x1 = x + script_position->get_w() + pad;
-       add_subwindow(script_scroll = new ScriptScroll(this, x1, y, get_w()-x1-pad));
-       y += script_scroll->get_h() + 2*pad;
-       x1 = x + pad;
+       x1 = x + script_position->get_w() + xpad;
+       add_subwindow(script_scroll = new ScriptScroll(this, x1, y, get_w()-x1-xpad));
+       y += script_scroll->get_h() + 2*ypad;
+       x1 = x + xpad;
        blank_line = new char[2];
        blank_line[0] = ' ';  blank_line[1] = 0;
        add_subwindow(script_title = new BC_Title(x1, y, _("Script Text:")));
-       y += script_title->get_h() + pad;
+       y += script_title->get_h() + ypad;
        int rows = (ok_y - y - BC_Title::calculate_h(this,_("Line Text:")) -
-               4*pad) / text_rowsz - 4;
-       int w1 = get_w() - x1 - pad;
+               4*ypad) / text_rowsz - 4;
+       int w1 = get_w() - x1 - xpad;
        script_entry = new ScriptEntry(this, x1, y, w1, rows, blank_line);
        script_entry->create_objects();
-       y += script_entry->get_h() + pad;
+       y += script_entry->get_h() + ypad;
        add_subwindow(line_title = new BC_Title(x1, y, _("Line Text:")));
-       y += line_title->get_h() + pad;
+       y += line_title->get_h() + ypad;
        line_entry = new ScriptEntry(this, x1, y, w1, 4);
        line_entry->create_objects();
        ok = new SWindowOK(this, ok_x, ok_y);
@@ -236,22 +258,23 @@ void SWindowGUI::load()
 }
 
 SWindowGUI::SWindowGUI(SWindow *swindow, int x, int y, int w, int h)
- : BC_Window(_(PROGRAM_NAME ": Subtitle"), x, y, w, h, 600, 500,
+ : BC_Window(_(PROGRAM_NAME ": Subtitle"), x, y, w, h, xS(600), yS(500),
        1, 0, 0 , -1, swindow->mwindow->get_cwindow_display())
 {
        this->swindow = swindow;
-       pad = 8;
+       xpad = xS(8);
+       ypad = yS(8);
 
        ok = 0;
        ok_w = BC_OKButton::calculate_w();
        ok_h = BC_OKButton::calculate_h();
-       ok_x = 10;
-       ok_y = h - ok_h - 10;
+       ok_x = xS(10);
+       ok_y = h - ok_h - yS(10);
        cancel = 0;
        cancel_w = BC_CancelButton::calculate_w();
        cancel_h = BC_CancelButton::calculate_h();
-       cancel_x = w - cancel_w - 10,
-       cancel_y = h - cancel_h - 10;
+       cancel_x = w - cancel_w - xS(10);
+       cancel_y = h - cancel_h - yS(10);
 
        load_path = 0;
        load_file = 0;
@@ -275,6 +298,9 @@ SWindowGUI::SWindowGUI(SWindow *swindow, int x, int y, int w, int h)
        blank_line = 0;
        text_font = MEDIUMFONT;
        text_rowsz = get_text_ascent(text_font)+1 + get_text_descent(text_font)+1;
+       sub_format = SUB_FORMAT_SRT;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Subtitles");
 }
 
 SWindowGUI::~SWindowGUI()
@@ -305,29 +331,29 @@ int SWindowGUI::resize_event(int w, int h)
        swindow->mwindow->session->swindow_w = w;
        swindow->mwindow->session->swindow_h = h;
 
-       ok_x = 10;
-       ok_y = h - ok_h - 10;
+       ok_x = xS(10);
+       ok_y = h - ok_h - yS(10);
        ok->reposition_window(ok_x, ok_y);
-       cancel_x = w - cancel_w - 10,
-       cancel_y = h - cancel_h - 10;
+       cancel_x = w - cancel_w - xS(10);
+       cancel_y = h - cancel_h - yS(10);
        cancel->reposition_window(cancel_x, cancel_y);
 
        int x = script_position->get_x();
        int y = script_position->get_y();
        int hh = script_position->get_h();
        int ww = script_position->get_w();
-       int x1 = x + ww + pad;
-       int w1 = w - x1 - pad;
+       int x1 = x + ww + xpad;
+       int w1 = w - x1 - xpad;
        script_scroll->reposition_window(x1, y, w1);
-       y += hh + 2*pad;
+       y += hh + 2*ypad;
        script_title->reposition_window(x, y);
-       y += script_title->get_h() + pad;
-       w1 = w - x - pad;
-       int rows = (ok_y - y - line_title->get_h() - 4*pad) / text_rowsz - 4;
+       y += script_title->get_h() + ypad;
+       w1 = w - x - xpad;
+       int rows = (ok_y - y - line_title->get_h() - 4*ypad) / text_rowsz - 4;
        script_entry->reposition_window(x, y, w1, rows);
-       y += script_entry->get_h() + 2*pad;
+       y += script_entry->get_h() + 2*ypad;
        line_title->reposition_window(x, y);
-       y += line_title->get_h() + pad;
+       y += line_title->get_h() + ypad;
        line_entry->reposition_window(x, y, w1, 4);
        return 0;
 }
@@ -338,6 +364,7 @@ void SWindowGUI::load_defaults()
        defaults->get("SUBTTL_SCRIPT_PATH", script_path);
        script_entry_no = defaults->get("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
        script_text_no = defaults->get("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
+       sub_format = defaults->get("SUBTTL_SCRIPT_FORMAT", sub_format);
 }
 
 void SWindowGUI::save_defaults()
@@ -346,6 +373,7 @@ void SWindowGUI::save_defaults()
        defaults->update("SUBTTL_SCRIPT_PATH", script_path);
        defaults->update("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
        defaults->update("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
+       defaults->update("SUBTTL_SCRIPT_FORMAT", sub_format);
 }
 
 void SWindowGUI::set_script_pos(int64_t entry_no, int text_no)
@@ -427,7 +455,7 @@ int SWindowGUI::update_selection()
        Edit *edit = 0;
        Tracks *tracks = edl->tracks;
        for( Track *track=tracks->first; track && !edit; track=track->next ) {
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
                if( track->data_type != TRACK_SUBTITLE ) continue;
                int64_t pos = track->to_units(position,0);
                edit = track->edits->editof(pos, PLAY_FORWARD, 0);
@@ -447,7 +475,7 @@ int MWindow::paste_subtitle_text(char *text, double start, double end)
        Tracks *tracks = edl->tracks;
        for( Track *track=tracks->first; track; track=track->next ) {
                if( track->data_type != TRACK_SUBTITLE ) continue;
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
                int64_t start_i = track->to_units(start, 0);
                int64_t end_i = track->to_units(end, 1);
                track->edits->clear(start_i,end_i);
@@ -461,7 +489,7 @@ int MWindow::paste_subtitle_text(char *text, double start, double end)
 
        sync_parameters(CHANGE_EDL);
        restart_brender();
-       gui->update(0, 1, 1, 0, 0, 0, 0);
+       gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
        gui->unlock_window();
 
        return 0;
@@ -837,35 +865,107 @@ void SWindowGUI::save_spumux_data()
        Tracks *tracks = swindow->mwindow->edl->tracks;
        for( Track *track=tracks->first; track; track=track->next ) {
                if( track->data_type != TRACK_SUBTITLE ) continue;
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
                char *cp = track_title, *ep = cp+sizeof(track_title)-6;
                for( const char *bp=track->title; cp<ep && *bp!=0; ) {
-                       int b = butf8(bp), c = !iswalnum(b) ? '_' : b;
-                       butf8(c, cp);
+                       int wch = butf8(bp); // iswalnum(wch) broken by MS port
+                       if( !( (wch >= 'A' && wch <= 'Z') ||
+                              (wch >= 'a' && wch <= 'z') ||
+                              (wch >= '0' && wch <= '9') ) ) wch = '_';
+                       butf8(wch, cp);
+               }
+               const char *sfx = "";
+               switch( sub_format ) {
+               case SUB_FORMAT_SRT:   sfx = ".srt";   break;
+               case SUB_FORMAT_RIP:   sfx = ".sub";   break;
+               case SUB_FORMAT_UDVD:  sfx = ".udvd";  break;
                }
                *cp = 0;
-               snprintf(ext,len,"-%s.udvd",track_title);
+               snprintf(ext,len,"-%s%s",track_title, sfx);
                FILE *fp = fopen(filename, "w");
                if( !fp ) {
                        eprintf(_("Unable to open %s:\n%m"), filename);
                        continue;
                }
-               int64_t start = 0;
+               switch( sub_format ) {
+               case SUB_FORMAT_RIP:
+                       fprintf(fp,"[SUBTITLE]\n"
+                               "[COLF]&HFFFFFF,[SIZE]12,[FONT]Times New Roman\n");
+                       break;
+               }
+               int64_t start = 0;  int count = 0;
                for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
                        SEdit *sedit = (SEdit *)edit;
-                       if( sedit->length > 0 ) {
-                               int64_t end = start + sedit->length;
-                               char *text = sedit->get_text();
-                               if( *text ) {
+                       if( !sedit->length ) continue;
+                       int64_t end = start + sedit->length;
+                       double st = sedit->track->from_units(start);
+                       int shr = st/3600; st -= shr*3600;
+                       int smn = st/60;   st -= smn*60;
+                       int ssc = st;      st -= ssc;
+                       int sms = st*1000;
+                       double et = sedit->track->from_units(end);
+                       int ehr = et/3600; et -= ehr*3600;
+                       int emn = et/60;   et -= emn*60;
+                       int esc = et;      et -= esc;
+                       int ems = et*1000;
+                       char *text = sedit->get_text();
+                       if( *text ) {
+                               ++count;
+                               switch( sub_format ) {
+                               case SUB_FORMAT_SRT:
+                                       fprintf(fp, "%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n",
+                                                count, shr, smn, ssc, sms, ehr, emn, esc, ems, text);
+                                       break;
+                               case SUB_FORMAT_RIP:
+                                       fprintf(fp, "%02d:%02d:%02d.%02d,%02d:%02d:%02d.%02d\n%s\n\n",
+                                                shr, smn, ssc, sms/10, ehr, emn, esc, ems/10, text);
+                                       break;
+                               case SUB_FORMAT_UDVD:
                                        fprintf(fp, "{%jd}{%jd}%s\n", start, end-1, text);
+                                       break;
                                }
-                               start = end;
                        }
+                       start = end;
                }
                fclose(fp);
        }
 }
 
+SWindowItemFormat::SWindowItemFormat(SWindowSaveFormat *save_format,
+               const char *text, int id)
+ : BC_MenuItem(text)
+{
+       this->save_format = save_format;
+       this->id = id;
+}
+
+int SWindowItemFormat::handle_event()
+{
+       save_format->sw_gui->sub_format = id;
+       save_format->update_toggles();
+       return 1;
+}
+
+SWindowSaveFormat::SWindowSaveFormat(SWindowGUI *sw_gui, int x, int y)
+ : BC_PopupMenu(x, y, _("Format"))
+{
+       this->sw_gui = sw_gui;
+}
+
+void SWindowSaveFormat::create_objects()
+{
+       add_item(srt = new SWindowItemFormat(this, _("SRT"), SUB_FORMAT_SRT));
+       add_item(rip = new SWindowItemFormat(this, _("SUB"), SUB_FORMAT_RIP));
+       add_item(udvd = new SWindowItemFormat(this, _("UDVD"), SUB_FORMAT_UDVD));
+       update_toggles();
+}
+
+void SWindowSaveFormat::update_toggles()
+{
+       srt->set_checked(sw_gui->sub_format == SUB_FORMAT_SRT);
+       rip->set_checked(sw_gui->sub_format == SUB_FORMAT_RIP);
+       udvd->set_checked(sw_gui->sub_format == SUB_FORMAT_UDVD);
+}
 
 
 SWindow::SWindow(MWindow *mwindow)
@@ -924,8 +1024,8 @@ void SWindow::run()
                int y = mwindow->session->swindow_y;
                int w = mwindow->session->swindow_w;
                int h = mwindow->session->swindow_h;
-               if( w < 600 ) w = 600;
-               if( h < 500 ) h = 500;
+               if( w < xS(600) ) w = xS(600);
+               if( h < yS(500) ) h = yS(500);
                int scr_x = mwindow->gui->get_screen_x(1, -1);
                int scr_w = mwindow->gui->get_screen_w(1, -1);
                if( x < scr_x ) x = scr_x;