3 * Copyright (C) 2016-2020 William Morrow
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 #include "condition.h"
26 #include "filesystem.h"
28 #include "localsession.h"
29 #include "mainerror.h"
31 #include "mainsession.h"
34 #include "mwindowgui.h"
49 SWindowOK::SWindowOK(SWindowGUI *gui, int x, int y)
55 SWindowOK::~SWindowOK()
59 int SWindowOK::button_press_event()
61 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
68 int SWindowOK::keypress_event()
70 return context_help_check_and_show();
74 SWindowCancel::SWindowCancel(SWindowGUI *gui, int x, int y)
75 : BC_CancelButton(x, y)
80 SWindowCancel::~SWindowCancel()
84 int SWindowCancel::button_press_event()
86 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
94 SWindowLoadPath::SWindowLoadPath(SWindowGUI *gui, int x, int y, char *path)
95 : BC_TextBox(x, y, xS(200), 1, path)
100 SWindowLoadPath::~SWindowLoadPath()
104 int SWindowLoadPath::handle_event()
106 calculate_suggestions();
107 strcpy(sw_gui->script_path, get_text());
112 SWindowLoadFile::SWindowLoadFile(SWindowGUI *gui, int x, int y)
113 : BC_GenericButton(x, y, _("Load"))
118 SWindowLoadFile::~SWindowLoadFile()
122 int SWindowLoadFile::handle_event()
124 if( sw_gui->script_path[0] ) {
125 sw_gui->load_path->set_suggestions(0,0);
126 sw_gui->load_script();
127 sw_gui->set_script_pos(0);
130 eprintf(_("script text file path required"));
135 SWindowSaveFile::SWindowSaveFile(SWindowGUI *gui, int x, int y)
136 : BC_GenericButton(x, y, _("Save"))
141 SWindowSaveFile::~SWindowSaveFile()
145 int SWindowSaveFile::handle_event()
147 if( sw_gui->script_path[0] ) {
148 sw_gui->save_spumux_data();
151 eprintf(_("script file path required"));
159 void SWindowGUI::create_objects()
161 lock_window("SWindowGUI::create_objects");
162 int x = xS(10), y = yS(10);
163 BC_Title *title = new BC_Title(x, y, _("Path:"));
164 add_subwindow(title);
165 int x1 = x + title->get_w() + xpad, y1 = y;
166 load_path = new SWindowLoadPath(this, x1, y1, script_path);
167 add_subwindow(load_path);
168 x1 += load_path->get_w() + 2*xpad;
169 add_subwindow(load_file = new SWindowLoadFile(this, x1, y1));
170 x1 += load_file->get_w() + 2*xpad;
171 add_subwindow(save_file = new SWindowSaveFile(this, x1, y1));
172 x1 += save_file->get_w() + 2*xpad;
173 add_subwindow(save_format = new SWindowSaveFormat(this, x1, y1));
174 save_format->create_objects();
175 y += max(load_path->get_h(), load_file->get_h()) + ypad;
176 x1 = x + ypad, y1 = y;
177 BC_Title *title1, *title2;
178 add_subwindow(title1 = new BC_Title(x1, y1, _("File Size:")));
179 y += title1->get_h() + ypad;
181 add_subwindow(title2 = new BC_Title(x1, y2, _("Entries:")));
182 int x2 = x1 + max(title1->get_w(), title2->get_w()) + xpad;
183 add_subwindow(script_filesz = new BC_Title(x2, y1, "0", MEDIUMFONT, YELLOW));
184 add_subwindow(script_entries = new BC_Title(x2, y2, "0", MEDIUMFONT, YELLOW));
185 int x3 = x2 + max(script_entries->get_w()*8, script_filesz->get_w()*8) + xpad;
186 add_subwindow(title1 = new BC_Title(x3, y1, _("Lines:")));
187 add_subwindow(title2 = new BC_Title(x3, y2, _("Texts:")));
188 int x4 = x3 + max(title1->get_w(), title2->get_w()) + xpad;
189 add_subwindow(script_lines = new BC_Title(x4, y1, "0", MEDIUMFONT, YELLOW));
190 add_subwindow(script_texts = new BC_Title(x4, y2, "0", MEDIUMFONT, YELLOW));
191 int x5 = x4 + max(script_lines->get_w()*8, script_texts->get_w()*8) + 2*xpad;
192 add_subwindow(prev_script = new ScriptPrev(this, x5, y1));
193 add_subwindow(next_script = new ScriptNext(this, x5, y2));
194 int x6 = x5 + max(prev_script->get_w(), next_script->get_w()) + 2*xpad;
195 add_subwindow(paste_script = new ScriptPaste(this, x6, y1));
196 add_subwindow(clear_script = new ScriptClear(this, x6, y2));
197 y += max(title1->get_h(), title2->get_h()) + 2*ypad;
199 script_position = new ScriptPosition(this, x, y, xS(100));
200 script_position->create_objects();
201 x1 = x + script_position->get_w() + xpad;
202 add_subwindow(script_scroll = new ScriptScroll(this, x1, y, get_w()-x1-xpad));
203 y += script_scroll->get_h() + 2*ypad;
205 blank_line = new char[2];
206 blank_line[0] = ' '; blank_line[1] = 0;
207 add_subwindow(script_title = new BC_Title(x1, y, _("Script Text:")));
208 y += script_title->get_h() + ypad;
209 int rows = (ok_y - y - BC_Title::calculate_h(this,_("Line Text:")) -
210 4*ypad) / text_rowsz - 4;
211 int w1 = get_w() - x1 - xpad;
212 script_entry = new ScriptEntry(this, x1, y, w1, rows, blank_line);
213 script_entry->create_objects();
214 y += script_entry->get_h() + ypad;
215 add_subwindow(line_title = new BC_Title(x1, y, _("Line Text:")));
216 y += line_title->get_h() + ypad;
217 line_entry = new ScriptEntry(this, x1, y, w1, 4);
218 line_entry->create_objects();
219 ok = new SWindowOK(this, ok_x, ok_y);
221 cancel = new SWindowCancel(this, cancel_x, cancel_y);
222 add_subwindow(cancel);
226 void SWindowGUI::load()
228 const char *script_text =
229 _("Adding Subtitles: quick \"How To\" (= or * indicates comment)\n"
230 "*2345678901234567890123456789012345678901234567890123456789\n"
231 "For regular DVD subtitles, put script in a text file. "
232 "Lines can be any length but they will be broken up "
233 "to fit according to some criteria below.\n"
234 "Running text used as script lines will be broken into multilple lines.\n"
235 "The target line length is 60 characters.\n"
236 "Punctuation may be flagged to create an early line break.\n"
237 "Single carriage return ends an individual script line.\n"
238 "Double carriage return indicates the end of an entry.\n"
239 "Whitespace at beginning or end of line is removed.\n"
240 "You can edit the active line in the Line Text box.\n"
242 "== A new entry is here for illustration purposes.\n"
244 "This is the second entry.\n");
246 if( script_path[0] && !access(script_path,R_OK) ) {
251 load_path->update(script_path);
252 FILE *fp = fmemopen((void *)script_text, strlen(script_text), "r");
255 int text_no = script_text_no;
257 load_selection(script_entry_no, text_no);
260 SWindowGUI::SWindowGUI(SWindow *swindow, int x, int y, int w, int h)
261 : BC_Window(_(PROGRAM_NAME ": Subtitle"), x, y, w, h, xS(600), yS(500),
262 1, 0, 0 , -1, swindow->mwindow->get_cwindow_display())
264 this->swindow = swindow;
269 ok_w = BC_OKButton::calculate_w();
270 ok_h = BC_OKButton::calculate_h();
272 ok_y = h - ok_h - yS(10);
274 cancel_w = BC_CancelButton::calculate_w();
275 cancel_h = BC_CancelButton::calculate_h();
276 cancel_x = w - cancel_w - xS(10);
277 cancel_y = h - cancel_h - yS(10);
289 script_text_lines = 0;
299 text_font = MEDIUMFONT;
300 text_rowsz = get_text_ascent(text_font)+1 + get_text_descent(text_font)+1;
301 sub_format = SUB_FORMAT_SRT;
302 // *** CONTEXT_HELP ***
303 context_help_set_keyword("Subtitles");
306 SWindowGUI::~SWindowGUI()
310 delete script_position;
311 delete [] blank_line;
314 void SWindowGUI::stop(int v)
316 if( !swindow->gui_done ) {
317 swindow->gui_done = 1;
322 int SWindowGUI::translation_event()
324 swindow->mwindow->session->swindow_x = get_x();
325 swindow->mwindow->session->swindow_y = get_y();
329 int SWindowGUI::resize_event(int w, int h)
331 swindow->mwindow->session->swindow_w = w;
332 swindow->mwindow->session->swindow_h = h;
335 ok_y = h - ok_h - yS(10);
336 ok->reposition_window(ok_x, ok_y);
337 cancel_x = w - cancel_w - xS(10);
338 cancel_y = h - cancel_h - yS(10);
339 cancel->reposition_window(cancel_x, cancel_y);
341 int x = script_position->get_x();
342 int y = script_position->get_y();
343 int hh = script_position->get_h();
344 int ww = script_position->get_w();
345 int x1 = x + ww + xpad;
346 int w1 = w - x1 - xpad;
347 script_scroll->reposition_window(x1, y, w1);
349 script_title->reposition_window(x, y);
350 y += script_title->get_h() + ypad;
352 int rows = (ok_y - y - line_title->get_h() - 4*ypad) / text_rowsz - 4;
353 script_entry->reposition_window(x, y, w1, rows);
354 y += script_entry->get_h() + 2*ypad;
355 line_title->reposition_window(x, y);
356 y += line_title->get_h() + ypad;
357 line_entry->reposition_window(x, y, w1, 4);
361 void SWindowGUI::load_defaults()
363 BC_Hash *defaults = swindow->mwindow->defaults;
364 defaults->get("SUBTTL_SCRIPT_PATH", script_path);
365 script_entry_no = defaults->get("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
366 script_text_no = defaults->get("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
367 sub_format = defaults->get("SUBTTL_SCRIPT_FORMAT", sub_format);
370 void SWindowGUI::save_defaults()
372 BC_Hash *defaults = swindow->mwindow->defaults;
373 defaults->update("SUBTTL_SCRIPT_PATH", script_path);
374 defaults->update("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
375 defaults->update("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
376 defaults->update("SUBTTL_SCRIPT_FORMAT", sub_format);
379 void SWindowGUI::set_script_pos(int64_t entry_no, int text_no)
381 script_entry_no = entry_no<0 ? 0 :
382 entry_no>script.size()-1 ? script.size()-1 : entry_no;
383 script_text_no = text_no-1;
384 load_next_selection();
387 int SWindowGUI::load_selection(int pos, int row)
389 if( pos < 0 || pos >= script.size() ) return 1;
390 ScriptLines *texts = script[pos];
391 char *rp = texts->get_text_row(row);
392 if( !rp || *rp == '=' || *rp == '*' || *rp=='\n' ) return 1;
393 if( pos != script_entry_no || script_text_no < 0 ) {
394 script_entry_no = pos;
395 script_scroll->update_value(script_entry_no);
396 script_position->update(script_entry_no);
397 script_entry->set_text(texts->text);
398 script_entry->set_text_row(0);
400 script_text_no = row;
401 char line[BCTEXTLEN], *bp = line;
402 char *ep = bp+sizeof(line)-1, *cp = rp;
403 while( bp < ep && *cp && *cp!='\n' ) *bp++ = *cp++;
404 *bp = 0; bp = texts->text;
405 int char1 = rp-bp, char2 = cp-bp;
406 script_entry->set_selection(char1, char2, char2);
407 int rows = script_entry->get_rows();
408 int rows2 = rows / 2;
409 int rows1 = texts->lines+1 - rows;
410 if( (row-=rows2) > rows1 ) row = rows1;
411 if( row < 0 ) row = 0;
412 script_entry->set_text_row(row);
413 line_entry->update(line);
414 line_entry->set_text_row(0);
418 int SWindowGUI::load_prev_selection()
420 int pos = script_entry_no, row = script_text_no;
421 if( pos < 0 || pos >= script.size() ) return 1;
424 if( --pos < 0 ) break;
425 row = script[pos]->lines;
428 if( !load_selection(pos, row) )
434 int SWindowGUI::load_next_selection()
436 int pos = script_entry_no, row = script_text_no;
437 if( pos < 0 || pos >= script.size() ) return 1;
439 if( ++row >= script[pos]->lines ) {
440 if( ++pos >= script.size() ) break;
444 if( !load_selection(pos, row) )
450 int SWindowGUI::update_selection()
452 EDL *edl = swindow->mwindow->edl;
453 LocalSession *lsn = edl->local_session;
454 double position = lsn->get_selectionstart();
456 Tracks *tracks = edl->tracks;
457 for( Track *track=tracks->first; track && !edit; track=track->next ) {
458 if( !track->is_armed() ) continue;
459 if( track->data_type != TRACK_SUBTITLE ) continue;
460 int64_t pos = track->to_units(position,0);
461 edit = track->edits->editof(pos, PLAY_FORWARD, 0);
463 if( !edit ) return 1;
464 SEdit *sedit = (SEdit *)edit;
465 line_entry->update(sedit->get_text());
466 line_entry->set_text_row(0);
470 int MWindow::paste_subtitle_text(char *text, double start, double end)
472 gui->lock_window("MWindow::paste_subtitle_text 1");
473 undo->update_undo_before();
475 Tracks *tracks = edl->tracks;
476 for( Track *track=tracks->first; track; track=track->next ) {
477 if( track->data_type != TRACK_SUBTITLE ) continue;
478 if( !track->is_armed() ) continue;
479 int64_t start_i = track->to_units(start, 0);
480 int64_t end_i = track->to_units(end, 1);
481 track->edits->clear(start_i,end_i);
482 SEdit *sedit = (SEdit *)track->edits->create_silence(start_i,end_i);
483 strcpy(sedit->get_text(),text);
484 track->edits->optimize();
488 undo->update_undo_after(_("paste subttl"), LOAD_EDITS | LOAD_PATCHES);
490 sync_parameters(CHANGE_EDL);
492 gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
493 gui->unlock_window();
498 int SWindowGUI::paste_text(const char *text, double start, double end)
500 char stext[BCTEXTLEN], *cp = stext;
501 if( text ) { // remap charset, reformat if needed
502 for( const char *bp=text; *bp!=0; ++bp,++cp ) {
504 case '\n': *cp = '|'; break;
505 default: *cp = *bp; break;
509 if( cp > stext && *(cp-1) == '|' ) --cp;
511 return swindow->mwindow->paste_subtitle_text(stext, start, end);
514 int SWindowGUI::paste_selection()
516 EDL *edl = swindow->mwindow->edl;
517 LocalSession *lsn = edl->local_session;
518 double start = lsn->get_selectionstart();
519 double end = lsn->get_selectionend();
520 if( start >= end ) return 1;
521 if( lsn->inpoint_valid() && lsn->outpoint_valid() ) {
522 lsn->set_inpoint(lsn->get_outpoint());
523 lsn->unset_outpoint();
525 paste_text(line_entry->get_text(), start, end);
526 load_next_selection();
530 int SWindowGUI::clear_selection()
532 EDL *edl = swindow->mwindow->edl;
533 double start = edl->local_session->get_selectionstart();
534 double end = edl->local_session->get_selectionend();
536 paste_text(0, start, end);
541 ScriptPrev::ScriptPrev(SWindowGUI *gui, int x, int y)
542 : BC_GenericButton(x, y, _("Prev"))
547 ScriptPrev::~ScriptPrev()
551 int ScriptPrev::handle_event()
553 sw_gui->load_prev_selection();
557 ScriptNext::ScriptNext(SWindowGUI *gui, int x, int y)
558 : BC_GenericButton(x, y, _("Next"))
563 ScriptNext::~ScriptNext()
567 int ScriptNext::handle_event()
569 sw_gui->load_next_selection();
573 ScriptPaste::ScriptPaste(SWindowGUI *gui, int x, int y)
574 : BC_GenericButton(x, y, _("Paste"))
579 ScriptPaste::~ScriptPaste()
583 int ScriptPaste::handle_event()
585 sw_gui->paste_selection();
589 ScriptClear::ScriptClear(SWindowGUI *gui, int x, int y)
590 : BC_GenericButton(x, y, _("Clear"))
595 ScriptClear::~ScriptClear()
599 int ScriptClear::handle_event()
601 sw_gui->clear_selection();
606 ScriptLines::ScriptLines()
610 text = new char[allocated = 256];
614 ScriptLines::~ScriptLines()
619 void ScriptLines::append(char *cp)
621 int len = strlen(cp);
622 if( allocated-used < len+1 ) {
623 int isz = allocated + used + len;
624 char *new_text = new char[isz];
626 memcpy(new_text, text, used);
627 delete [] text; text = new_text;
629 memcpy(text+used, cp, len);
630 text[used += len] = 0;
634 int ScriptLines::break_lines()
637 int limit2 = line_limit/2;
638 int limit4 = line_limit/4-2;
639 char *cp = text, *dp = cp+used;
640 int n; char *bp, *ep, *pp, *sp;
641 for( lines=0; cp<dp; ++lines ) {
642 // find end of line/buffer
643 for( ep=cp; ep<dp && *ep!='\n'; ++ep );
644 // delete trailing spaces
645 for( sp=ep; sp>=cp && (!*sp || isspace(*sp)); --sp);
647 if( (n=ep-sp) > 0 ) {
648 memmove(sp,ep,dp+1-ep);
649 used -= n; dp -= n; ep -= n;
652 // skip, if comment or title line
653 if( *cp == '*' || *cp == '=' ) {
656 // delete leading spaces
657 for( sp=cp; sp<ep && isspace(*sp); ++sp);
658 if( (n=sp-cp) > 0 ) {
659 memmove(cp,sp,dp+1-sp);
660 used -= n; dp -= n; ep -= n;
662 // target about half remaining line, constrain line_limit
663 if( (n=(ep-1-cp)/2) < limit2 || n > line_limit )
665 // search for last punct, last space before line_limit
666 for( bp=cp, pp=sp=0; --n>=0 && cp<ep; ++cp ) {
667 if( ispunct(*cp) && isspace(*(cp+1)) ) pp = cp;
668 else if( isspace(*cp) ) sp = cp;
672 // first, after punctuation
673 if( pp && pp-bp >= limit4 )
679 // last, on next space
681 while( cp<dp && !isspace(*cp) ) ++cp;
691 int ScriptLines::get_text_rows()
694 for( char *cp=text; --i>=0; ++cp )
695 if( *cp == '\n' ) ++ret;
699 char *ScriptLines::get_text_row(int n)
703 for( int i=used; --i>=0; ) {
704 if( *cp++ != '\n' ) continue;
705 if( --n <= 0 ) return cp;
710 ScriptScroll::ScriptScroll(SWindowGUI *gui, int x, int y, int w)
711 : BC_ScrollBar(x, y, SCROLL_HORIZ + SCROLL_STRETCH, w, 0, 0, 0)
716 ScriptScroll::~ScriptScroll()
720 int ScriptScroll::handle_event()
722 int64_t pos = get_value();
723 sw_gui->set_script_pos(pos);
724 sw_gui->script_position->update(pos);
729 ScriptPosition::ScriptPosition(SWindowGUI *gui, int x, int y, int w, int v, int mn, int mx)
730 : BC_TumbleTextBox(gui, v, mn, mx, x, y, w-BC_Tumbler::calculate_w())
735 ScriptPosition::~ScriptPosition()
739 int ScriptPosition::handle_event()
741 int64_t pos = atol(get_text());
742 sw_gui->set_script_pos(pos);
743 sw_gui->script_scroll->update_value(pos);
748 ScriptEntry::ScriptEntry(SWindowGUI *gui, int x, int y, int w, int rows, char *text)
749 : BC_ScrollTextBox(gui, x, y, w, rows, text, -strlen(text))
755 ScriptEntry::ScriptEntry(SWindowGUI *gui, int x, int y, int w, int rows)
756 : BC_ScrollTextBox(gui, x, y, w, rows,(char*)0, BCTEXTLEN)
762 ScriptEntry::~ScriptEntry()
766 void ScriptEntry::set_text(char *text, int isz)
768 if( !text || !*text ) return;
769 if( isz < 0 ) isz = strlen(text)+1;
770 BC_ScrollTextBox::set_text(text, isz);
774 int ScriptEntry::handle_event()
776 if( ttext && sw_gui->get_button_down() &&
777 sw_gui->get_buttonpress() == 1 &&
778 sw_gui->get_triple_click() ) {
779 int ibeam = get_ibeam_letter(), row = 0;
780 const char *tp = ttext;
781 while( *tp && tp-ttext < ibeam ) {
782 if( *tp++ == '\n' ) ++row;
784 int pos = sw_gui->script_entry_no;
785 sw_gui->load_selection(pos, row);
790 int SWindowGUI::load_script_line(FILE *fp)
793 for(;;) { // skip blank lines
794 char *cp = fgets(line,sizeof(line),fp);
797 while( *cp && isspace(*cp) ) ++cp;
801 ScriptLines *entry = new ScriptLines();
802 script.append(entry);
804 for(;;) { // load non-blank lines
805 //int len = strlen(line);
806 //if( line[len-1] == '\n' ) line[len-1] = ' ';
808 char *cp = fgets(line,sizeof(line),fp);
811 while( *cp && isspace(*cp) ) ++cp;
814 script_text_lines += entry->break_lines();
818 void SWindowGUI::load_script()
820 FILE *fp = fopen(script_path,"r");
822 char string[BCTEXTLEN];
823 sprintf(string,_("cannot open: \"%s\"\n%s"),script_path,strerror(errno));
824 MainError::show_error(string);
829 load_selection(script_entry_no=0, 0);
832 void SWindowGUI::load_script(FILE *fp)
834 script.remove_all_objects();
836 script_text_lines = 0;
837 while( !load_script_line(fp) );
839 sprintf(value,"%ld",ftell(fp));
840 script_filesz->update(value);
841 sprintf(value,"%jd",script_line_no);
842 script_lines->update(value);
843 sprintf(value,"%d",script.size());
844 script_entries->update(value);
845 sprintf(value,"%jd",script_text_lines);
846 script_texts->update(value);
847 int hw = script_scroll->get_h();
848 script_scroll->update_length(script.size(), script_entry_no, hw, 0);
849 script_position->update(script_entry_no);
850 script_position->set_boundaries((int64_t)0, (int64_t)script.size()-1);
854 void SWindowGUI::save_spumux_data()
856 char filename[BCTEXTLEN], track_title[BCTEXTLEN];
857 snprintf(filename,sizeof(filename),"%s",script_path);
858 filename[sizeof(filename)-1] = 0;
859 char *bp = strrchr(filename,'/');
860 if( !bp ) bp = filename; else ++bp;
861 char *ext = strrchr(bp, '.');
862 if( !ext ) ext = bp + strlen(bp);
863 int len = sizeof(filename)-1 - (ext-filename);
865 Tracks *tracks = swindow->mwindow->edl->tracks;
866 for( Track *track=tracks->first; track; track=track->next ) {
867 if( track->data_type != TRACK_SUBTITLE ) continue;
868 if( !track->is_armed() ) continue;
869 char *cp = track_title, *ep = cp+sizeof(track_title)-6;
870 for( const char *bp=track->title; cp<ep && *bp!=0; ) {
871 int wch = butf8(bp); // iswalnum(wch) broken by MS port
872 if( !( (wch >= 'A' && wch <= 'Z') ||
873 (wch >= 'a' && wch <= 'z') ||
874 (wch >= '0' && wch <= '9') ) ) wch = '_';
877 const char *sfx = "";
878 switch( sub_format ) {
879 case SUB_FORMAT_SRT: sfx = ".srt"; break;
880 case SUB_FORMAT_RIP: sfx = ".sub"; break;
881 case SUB_FORMAT_UDVD: sfx = ".udvd"; break;
884 snprintf(ext,len,"-%s%s",track_title, sfx);
885 FILE *fp = fopen(filename, "w");
887 eprintf(_("Unable to open %s:\n%m"), filename);
890 switch( sub_format ) {
892 fprintf(fp,"[SUBTITLE]\n"
893 "[COLF]&HFFFFFF,[SIZE]12,[FONT]Times New Roman\n");
896 int64_t start = 0; int count = 0;
897 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
898 SEdit *sedit = (SEdit *)edit;
899 if( !sedit->length ) continue;
900 int64_t end = start + sedit->length;
901 double st = sedit->track->from_units(start);
902 int shr = st/3600; st -= shr*3600;
903 int smn = st/60; st -= smn*60;
904 int ssc = st; st -= ssc;
906 double et = sedit->track->from_units(end);
907 int ehr = et/3600; et -= ehr*3600;
908 int emn = et/60; et -= emn*60;
909 int esc = et; et -= esc;
911 char *text = sedit->get_text();
914 switch( sub_format ) {
916 fprintf(fp, "%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n",
917 count, shr, smn, ssc, sms, ehr, emn, esc, ems, text);
920 fprintf(fp, "%02d:%02d:%02d.%02d,%02d:%02d:%02d.%02d\n%s\n\n",
921 shr, smn, ssc, sms/10, ehr, emn, esc, ems/10, text);
923 case SUB_FORMAT_UDVD:
924 fprintf(fp, "{%jd}{%jd}%s\n", start, end-1, text);
934 SWindowItemFormat::SWindowItemFormat(SWindowSaveFormat *save_format,
935 const char *text, int id)
938 this->save_format = save_format;
942 int SWindowItemFormat::handle_event()
944 save_format->sw_gui->sub_format = id;
945 save_format->update_toggles();
949 SWindowSaveFormat::SWindowSaveFormat(SWindowGUI *sw_gui, int x, int y)
950 : BC_PopupMenu(x, y, _("Format"))
952 this->sw_gui = sw_gui;
955 void SWindowSaveFormat::create_objects()
957 add_item(srt = new SWindowItemFormat(this, _("SRT"), SUB_FORMAT_SRT));
958 add_item(rip = new SWindowItemFormat(this, _("SUB"), SUB_FORMAT_RIP));
959 add_item(udvd = new SWindowItemFormat(this, _("UDVD"), SUB_FORMAT_UDVD));
963 void SWindowSaveFormat::update_toggles()
965 srt->set_checked(sw_gui->sub_format == SUB_FORMAT_SRT);
966 rip->set_checked(sw_gui->sub_format == SUB_FORMAT_RIP);
967 udvd->set_checked(sw_gui->sub_format == SUB_FORMAT_UDVD);
971 SWindow::SWindow(MWindow *mwindow)
974 this->mwindow = mwindow;
975 window_lock = new Mutex("SWindow::window_lock");
976 swin_lock = new Condition(0,"SWindow::swin_lock");
993 void SWindow::start()
995 if( !Thread::running() ) {
1001 void SWindow::stop()
1003 if( Thread::running() ) {
1005 swin_lock->unlock();
1006 window_lock->lock("SWindow::stop");
1007 if( gui ) gui->stop(1);
1008 window_lock->unlock();
1016 int root_w = mwindow->gui->get_root_w(1);
1017 int root_h = mwindow->gui->get_root_h(1);
1023 int x = mwindow->session->swindow_x;
1024 int y = mwindow->session->swindow_y;
1025 int w = mwindow->session->swindow_w;
1026 int h = mwindow->session->swindow_h;
1027 if( w < xS(600) ) w = xS(600);
1028 if( h < yS(500) ) h = yS(500);
1029 int scr_x = mwindow->gui->get_screen_x(1, -1);
1030 int scr_w = mwindow->gui->get_screen_w(1, -1);
1031 if( x < scr_x ) x = scr_x;
1032 if( x > scr_x+scr_w ) x = scr_x+scr_w;
1033 if( x+w > root_w ) x = root_w - w;
1034 if( x < 0 ) { x = 0; w = scr_w; }
1035 if( y+h > root_h ) y = root_h - h;
1036 if( y < 0 ) { y = 0; h = root_h; }
1037 if( y+h > root_h ) h = root_h-y;
1038 mwindow->session->swindow_x = x;
1039 mwindow->session->swindow_y = y;
1040 mwindow->session->swindow_w = w;
1041 mwindow->session->swindow_h = h;
1044 gui = new SWindowGUI(this, x, y, w, h);
1045 gui->lock_window("ChannelInfo::gui_create_objects");
1046 gui->load_defaults();
1047 gui->create_objects();
1048 gui->set_icon(mwindow->theme->get_image("record_icon"));
1049 gui->reposition_window(x, y);
1050 gui->resize_event(w, h);
1053 gui->unlock_window();
1055 int result = gui->run_window();
1057 gui->save_spumux_data();
1060 window_lock->lock("ChannelInfo::run 1");
1061 gui->save_defaults();
1062 delete gui; gui = 0;
1063 window_lock->unlock();
1070 void SWindow::run_swin()
1072 window_lock->lock("SWindow::run_swin");
1074 gui->lock_window("SWindow::run_swin");
1075 gui->raise_window();
1076 gui->unlock_window();
1079 swin_lock->unlock();
1080 window_lock->unlock();
1083 void SWindow::paste_subttl()
1085 window_lock->lock("SWindow::paste_subttl 1");
1087 gui->lock_window("SWindow::paste_subttl 2");
1088 gui->paste_selection();
1089 gui->unlock_window();
1091 window_lock->unlock();
1094 int SWindow::update_selection()
1096 window_lock->lock("SWindow::update_selection 1");
1098 gui->lock_window("SWindow::update_selection 2");
1099 gui->update_selection();
1100 gui->unlock_window();
1102 window_lock->unlock();
1108 SubttlSWin::SubttlSWin(MWindow *mwindow)
1109 : BC_MenuItem(_("SubTitle..."), _("Alt-y"), 'y')
1112 this->mwindow = mwindow;
1115 SubttlSWin::~SubttlSWin()
1119 int SubttlSWin::handle_event()
1121 mwindow->gui->swindow->run_swin();