7 #include "filesystem.h"
8 #include "localsession.h"
11 #include "mainsession.h"
14 #include "mwindowgui.h"
29 SWindowOK::SWindowOK(SWindowGUI *gui, int x, int y)
35 SWindowOK::~SWindowOK()
39 int SWindowOK::button_press_event()
41 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
48 int SWindowOK::keypress_event()
54 SWindowCancel::SWindowCancel(SWindowGUI *gui, int x, int y)
55 : BC_CancelButton(x, y)
60 SWindowCancel::~SWindowCancel()
64 int SWindowCancel::button_press_event()
66 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
74 SWindowLoadPath::SWindowLoadPath(SWindowGUI *gui, int x, int y, char *path)
75 : BC_TextBox(x, y, 200, 1, path)
79 file_entries = new ArrayList<BC_ListBoxItem*>;
80 FileSystem fs; char string[BCTEXTLEN];
81 // Load current directory
82 fs.update(getcwd(string, BCTEXTLEN));
83 int total_files = fs.total_files();
84 for(int i = 0; i < total_files; i++) {
85 const char *name = fs.get_entry(i)->get_name();
86 file_entries->append(new BC_ListBoxItem(name));
90 SWindowLoadPath::~SWindowLoadPath()
92 file_entries->remove_all_objects();
96 int SWindowLoadPath::handle_event()
98 calculate_suggestions(file_entries);
99 strcpy(sw_gui->script_path, get_text());
104 SWindowLoadFile::SWindowLoadFile(SWindowGUI *gui, int x, int y)
105 : BC_GenericButton(x, y, _("Load"))
110 SWindowLoadFile::~SWindowLoadFile()
114 int SWindowLoadFile::handle_event()
116 sw_gui->load_path->set_suggestions(0,0);
117 sw_gui->load_script();
118 sw_gui->set_script_pos(0);
122 SWindowSaveFile::SWindowSaveFile(SWindowGUI *gui, int x, int y)
123 : BC_GenericButton(x, y, _("Save"))
128 SWindowSaveFile::~SWindowSaveFile()
132 int SWindowSaveFile::handle_event()
134 sw_gui->save_spumux_data();
141 void SWindowGUI::create_objects()
144 BC_Title *title = new BC_Title(x, y, _("Path:"));
145 add_subwindow(title);
146 int x1 = x + title->get_w() + pad, y1 = y;
147 load_path = new SWindowLoadPath(this, x1, y1, script_path);
148 add_subwindow(load_path);
149 x1 += load_path->get_w() + 2*pad;
150 add_subwindow(load_file = new SWindowLoadFile(this, x1, y1));
151 x1 += load_file->get_w() + 2*pad;
152 add_subwindow(save_file = new SWindowSaveFile(this, x1, y1));
153 y += max(load_path->get_h(), load_file->get_h()) + pad;
154 x1 = x + pad, y1 = y;
155 BC_Title *title1, *title2;
156 add_subwindow(title1 = new BC_Title(x1, y1, _("File Size:")));
157 y += title1->get_h() + pad;
159 add_subwindow(title2 = new BC_Title(x1, y2, _("Entries:")));
160 int x2 = x1 + max(title1->get_w(), title2->get_w()) + pad;
161 add_subwindow(script_filesz = new BC_Title(x2, y1, "0", MEDIUMFONT, YELLOW));
162 add_subwindow(script_entries = new BC_Title(x2, y2, "0", MEDIUMFONT, YELLOW));
163 int x3 = x2 + max(script_entries->get_w()*8, script_filesz->get_w()*8) + pad;
164 add_subwindow(title1 = new BC_Title(x3, y1, _("Lines:")));
165 add_subwindow(title2 = new BC_Title(x3, y2, _("Texts:")));
166 int x4 = x3 + max(title1->get_w(), title2->get_w()) + pad;
167 add_subwindow(script_lines = new BC_Title(x4, y1, "0", MEDIUMFONT, YELLOW));
168 add_subwindow(script_texts = new BC_Title(x4, y2, "0", MEDIUMFONT, YELLOW));
169 int x5 = x4 + max(script_lines->get_w()*8, script_texts->get_w()*8) + 2*pad;
170 add_subwindow(prev_script = new ScriptPrev(this, x5, y1));
171 add_subwindow(next_script = new ScriptNext(this, x5, y2));
172 int x6 = x5 + max(prev_script->get_w(), next_script->get_w()) + 2*pad;
173 add_subwindow(paste_script = new ScriptPaste(this, x6, y1));
174 add_subwindow(clear_script = new ScriptClear(this, x6, y2));
175 y += max(title1->get_h(), title2->get_h()) + 2*pad;
177 script_position = new ScriptPosition(this, x, y, 100);
178 script_position->create_objects();
179 x1 = x + script_position->get_w() + pad;
180 add_subwindow(script_scroll = new ScriptScroll(this, x1, y, get_w()-x1-pad));
181 y += script_scroll->get_h() + 2*pad;
183 blank_line = new char[2];
184 blank_line[0] = ' '; blank_line[1] = 0;
185 int rows = (ok_y - y - 4*pad) / text_rowsz - 3;
186 int w1 = get_w()-x1-pad;
187 script_entry = new ScriptEntry(this, x1, y, w1, rows, blank_line);
188 script_entry->create_objects();
189 y += script_entry->get_h() + pad;
190 line_entry = new ScriptEntry(this, x1, y, w1, 3);
191 line_entry->create_objects();
192 ok = new SWindowOK(this, ok_x, ok_y);
194 cancel = new SWindowCancel(this, cancel_x, cancel_y);
195 add_subwindow(cancel);
198 void SWindowGUI::load()
200 if( script_path[0] && !access(script_path,R_OK) ) {
202 int text_no = script_text_no;
204 load_selection(script_entry_no, text_no);
207 script.remove_all_objects();
209 load_path->update(script_path);
215 SWindowGUI::SWindowGUI(SWindow *swindow, int x, int y, int w, int h)
216 : BC_Window(_(PROGRAM_NAME ": Subtitle"), x, y, w, h, 600, 500,
217 1, 0, 0 , -1, swindow->mwindow->get_cwindow_display())
219 this->swindow = swindow;
223 ok_w = BC_OKButton::calculate_w();
224 ok_h = BC_OKButton::calculate_h();
226 ok_y = h - ok_h - 10;
228 cancel_w = BC_CancelButton::calculate_w();
229 cancel_h = BC_CancelButton::calculate_h();
230 cancel_x = w - cancel_w - 10,
231 cancel_y = h - cancel_h - 10;
243 script_text_lines = 0;
253 text_font = MEDIUMFONT;
254 text_rowsz = get_text_ascent(text_font)+1 + get_text_descent(text_font)+1;
257 SWindowGUI::~SWindowGUI()
261 delete script_position;
262 delete [] blank_line;
265 void SWindowGUI::stop(int v)
267 if( !swindow->gui_done ) {
268 swindow->gui_done = 1;
273 int SWindowGUI::translation_event()
275 swindow->mwindow->session->swindow_x = get_x();
276 swindow->mwindow->session->swindow_y = get_y();
280 int SWindowGUI::resize_event(int w, int h)
282 swindow->mwindow->session->swindow_w = w;
283 swindow->mwindow->session->swindow_h = h;
286 ok_y = h - ok_h - 10;
287 ok->reposition_window(ok_x, ok_y);
288 cancel_x = w - cancel_w - 10,
289 cancel_y = h - cancel_h - 10;
290 cancel->reposition_window(cancel_x, cancel_y);
292 int x = script_position->get_x();
293 int y = script_position->get_y();
294 int hh = script_position->get_h();
295 int ww = script_position->get_w();
296 int x1 = x + ww + pad;
297 int w1 = w - x1 - pad;
298 script_scroll->reposition_window(x1, y, w1);
301 int rows = (ok_y - y - 4*pad) / text_rowsz - 3;
302 script_entry->reposition_window(x, y, w1, rows);
303 y += script_entry->get_h() + pad;
304 line_entry->reposition_window(x, y, w1, 3);
308 void SWindowGUI::load_defaults()
310 BC_Hash *defaults = swindow->mwindow->defaults;
311 defaults->get("SUBTTL_SCRIPT_PATH", script_path);
312 script_entry_no = defaults->get("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
313 script_text_no = defaults->get("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
316 void SWindowGUI::save_defaults()
318 BC_Hash *defaults = swindow->mwindow->defaults;
319 defaults->update("SUBTTL_SCRIPT_PATH", script_path);
320 defaults->update("SUBTTL_SCRIPT_ENTRY_NO", script_entry_no);
321 defaults->update("SUBTTL_SCRIPT_TEXT_NO", script_text_no);
324 void SWindowGUI::set_script_pos(int64_t entry_no, int text_no)
326 script_entry_no = entry_no<0 ? 0 :
327 entry_no>script.size()-1 ? script.size()-1 : entry_no;
328 script_text_no = text_no-1;
329 load_next_selection();
332 int SWindowGUI::load_selection(int pos, int row)
334 ScriptLines *texts = script[pos];
335 char *rp = texts->get_text_row(row);
336 if( !rp || *rp == '=' || *rp == '*' || *rp=='\n' ) return 1;
337 if( pos != script_entry_no || script_text_no < 0 ) {
338 script_entry_no = pos;
339 script_scroll->update_value(script_entry_no);
340 script_position->update(script_entry_no);
341 script_entry->set_text(texts->text);
342 script_entry->set_text_row(0);
344 script_text_no = row;
345 char line[BCTEXTLEN], *bp = line;
346 char *ep = bp+sizeof(line)-1, *cp = rp;
347 while( bp < ep && *cp && *cp!='\n' ) *bp++ = *cp++;
348 *bp = 0; bp = texts->text;
349 int char1 = rp-bp, char2 = cp-bp;
350 script_entry->set_selection(char1, char2, char2);
351 int rows = script_entry->get_rows();
352 int rows2 = rows / 2;
353 int rows1 = texts->lines+1 - rows;
354 if( (row-=rows2) > rows1 ) row = rows1;
355 if( row < 0 ) row = 0;
356 script_entry->set_text_row(row);
357 line_entry->update(line);
358 line_entry->set_text_row(0);
362 int SWindowGUI::load_prev_selection()
364 int pos = script_entry_no, row = script_text_no;
365 if( pos < 0 || pos >= script.size() ) return 1;
368 if( --pos < 0 ) break;
369 row = script[pos]->lines;
372 if( !load_selection(pos, row) )
378 int SWindowGUI::load_next_selection()
380 int pos = script_entry_no, row = script_text_no;
381 if( pos < 0 || pos >= script.size() ) return 1;
383 if( ++row >= script[pos]->lines ) {
384 if( ++pos >= script.size() ) break;
388 if( !load_selection(pos, row) )
394 int SWindowGUI::update_selection()
396 EDL *edl = swindow->mwindow->edl;
397 LocalSession *lsn = edl->local_session;
398 double position = lsn->get_selectionstart();
400 Tracks *tracks = edl->tracks;
401 for( Track *track=tracks->first; track && !edit; track=track->next ) {
402 if( !track->record ) continue;
403 if( track->data_type != TRACK_SUBTITLE ) continue;
404 int64_t pos = track->to_units(position,0);
405 edit = track->edits->editof(pos, PLAY_FORWARD, 0);
407 if( !edit ) return 1;
408 SEdit *sedit = (SEdit *)edit;
409 line_entry->update(sedit->get_text());
410 line_entry->set_text_row(0);
414 int MWindow::paste_subtitle_text(char *text, double start, double end)
416 gui->lock_window("MWindow::paste_subtitle_text 1");
417 undo->update_undo_before();
419 Tracks *tracks = edl->tracks;
420 for( Track *track=tracks->first; track; track=track->next ) {
421 if( track->data_type != TRACK_SUBTITLE ) continue;
422 if( !track->record ) continue;
423 int64_t start_i = track->to_units(start, 0);
424 int64_t end_i = track->to_units(end, 1);
425 track->edits->clear(start_i,end_i);
426 SEdit *sedit = (SEdit *)track->edits->create_silence(start_i,end_i);
427 strcpy(sedit->get_text(),text);
428 track->edits->optimize();
432 undo->update_undo_after(_("paste subttl"), LOAD_EDITS | LOAD_PATCHES);
434 sync_parameters(CHANGE_EDL);
436 gui->update(0, 1, 1, 0, 0, 0, 0);
437 gui->unlock_window();
442 int SWindowGUI::paste_text(const char *text, double start, double end)
444 char stext[BCTEXTLEN], *cp = stext;
445 if( text ) { // remap charset, reformat if needed
446 for( const char *bp=text; *bp!=0; ++bp,++cp ) {
448 case '\n': *cp = '|'; break;
449 default: *cp = *bp; break;
453 if( cp > stext && *(cp-1) == '|' ) --cp;
455 return swindow->mwindow->paste_subtitle_text(stext, start, end);
458 int SWindowGUI::paste_selection()
460 EDL *edl = swindow->mwindow->edl;
461 LocalSession *lsn = edl->local_session;
462 double start = lsn->get_selectionstart();
463 double end = lsn->get_selectionend();
464 if( start >= end ) return 1;
465 if( lsn->inpoint_valid() && lsn->outpoint_valid() ) {
466 lsn->set_inpoint(lsn->get_outpoint());
467 lsn->unset_outpoint();
469 paste_text(line_entry->get_text(), start, end);
470 load_next_selection();
474 int SWindowGUI::clear_selection()
476 EDL *edl = swindow->mwindow->edl;
477 double start = edl->local_session->get_selectionstart();
478 double end = edl->local_session->get_selectionend();
480 paste_text(0, start, end);
485 ScriptPrev::ScriptPrev(SWindowGUI *gui, int x, int y)
486 : BC_GenericButton(x, y, _("Prev"))
491 ScriptPrev::~ScriptPrev()
495 int ScriptPrev::handle_event()
497 sw_gui->load_prev_selection();
501 ScriptNext::ScriptNext(SWindowGUI *gui, int x, int y)
502 : BC_GenericButton(x, y, _("Next"))
507 ScriptNext::~ScriptNext()
511 int ScriptNext::handle_event()
513 sw_gui->load_next_selection();
517 ScriptPaste::ScriptPaste(SWindowGUI *gui, int x, int y)
518 : BC_GenericButton(x, y, _("Paste"))
523 ScriptPaste::~ScriptPaste()
527 int ScriptPaste::handle_event()
529 sw_gui->paste_selection();
533 ScriptClear::ScriptClear(SWindowGUI *gui, int x, int y)
534 : BC_GenericButton(x, y, _("Clear"))
539 ScriptClear::~ScriptClear()
543 int ScriptClear::handle_event()
545 sw_gui->clear_selection();
550 ScriptLines::ScriptLines()
554 text = new char[allocated = 256];
558 ScriptLines::~ScriptLines()
563 void ScriptLines::append(char *cp)
565 int len = strlen(cp);
566 if( allocated-used < len+1 ) {
567 int isz = allocated + used + len;
568 char *new_text = new char[isz];
570 memcpy(new_text, text, used);
571 delete [] text; text = new_text;
573 memcpy(text+used, cp, len);
574 text[used += len] = 0;
578 int ScriptLines::break_lines()
581 int limit2 = line_limit/2;
582 int limit4 = line_limit/4-2;
583 char *cp = text, *dp = cp+used;
584 int n; char *bp, *ep, *pp, *sp;
585 for( lines=0; cp<dp; ++lines ) {
586 // find end of line/buffer
587 for( ep=cp; ep<dp && *ep!='\n'; ++ep );
588 // delete trailing spaces
589 for( sp=ep; sp>=cp && (!*sp || isspace(*sp)); --sp);
591 if( (n=ep-sp) > 0 ) {
592 memmove(sp,ep,dp+1-ep);
593 used -= n; dp -= n; ep -= n;
596 // skip, if comment or title line
597 if( *cp == '*' || *cp == '=' ) {
600 // delete leading spaces
601 for( sp=cp; sp<ep && isspace(*sp); ++sp);
602 if( (n=sp-cp) > 0 ) {
603 memmove(cp,sp,dp+1-sp);
604 used -= n; dp -= n; ep -= n;
606 // target about half remaining line, constrain line_limit
607 if( (n=(ep-1-cp)/2) < limit2 || n > line_limit )
609 // search for last punct, last space before line_limit
610 for( bp=cp, pp=sp=0; --n>=0 && cp<ep; ++cp ) {
611 if( ispunct(*cp) && isspace(*(cp+1)) ) pp = cp;
612 else if( isspace(*cp) ) sp = cp;
616 // first, after punctuation
617 if( pp && pp-bp >= limit4 )
623 // last, on next space
625 while( cp<dp && !isspace(*cp) ) ++cp;
635 int ScriptLines::get_text_rows()
638 for( char *cp=text; --i>=0; ++cp )
639 if( *cp == '\n' ) ++ret;
643 char *ScriptLines::get_text_row(int n)
647 for( int i=used; --i>=0; ) {
648 if( *cp++ != '\n' ) continue;
649 if( --n <= 0 ) return cp;
654 ScriptScroll::ScriptScroll(SWindowGUI *gui, int x, int y, int w)
655 : BC_ScrollBar(x, y, SCROLL_HORIZ, w, 0, 0, 0)
660 ScriptScroll::~ScriptScroll()
664 int ScriptScroll::handle_event()
666 int64_t pos = get_value();
667 sw_gui->set_script_pos(pos);
668 sw_gui->script_position->update(pos);
673 ScriptPosition::ScriptPosition(SWindowGUI *gui, int x, int y, int w, int v, int mn, int mx)
674 : BC_TumbleTextBox(gui, v, mn, mx, x, y, w-BC_Tumbler::calculate_w())
679 ScriptPosition::~ScriptPosition()
683 int ScriptPosition::handle_event()
685 int64_t pos = atol(get_text());
686 sw_gui->set_script_pos(pos);
687 sw_gui->script_scroll->update_value(pos);
692 ScriptEntry::ScriptEntry(SWindowGUI *gui, int x, int y, int w, int rows, char *text)
693 : BC_ScrollTextBox(gui, x, y, w, rows, text, -strlen(text))
699 ScriptEntry::ScriptEntry(SWindowGUI *gui, int x, int y, int w, int rows)
700 : BC_ScrollTextBox(gui, x, y, w, rows,(char*)0, BCTEXTLEN)
706 ScriptEntry::~ScriptEntry()
710 void ScriptEntry::set_text(char *text, int isz)
712 if( !text || !*text ) return;
713 if( isz < 0 ) isz = strlen(text);
714 BC_ScrollTextBox::set_text(text, isz);
719 int SWindowGUI::load_script_line(FILE *fp)
722 for(;;) { // skip blank lines
723 char *cp = fgets(line,sizeof(line),fp);
726 while( *cp && isspace(*cp) ) ++cp;
730 ScriptLines *entry = new ScriptLines();
731 script.append(entry);
733 for(;;) { // load non-blank lines
734 //int len = strlen(line);
735 //if( line[len-1] == '\n' ) line[len-1] = ' ';
737 char *cp = fgets(line,sizeof(line),fp);
740 while( *cp && isspace(*cp) ) ++cp;
743 script_text_lines += entry->break_lines();
747 void SWindowGUI::load_script()
749 FILE *fp = fopen(script_path,"r");
751 char string[BCTEXTLEN];
752 sprintf(string,_("cannot open: \"%s\"\n%s"),script_path,strerror(errno));
753 MainError::show_error(string);
757 script.remove_all_objects();
759 script_text_lines = 0;
760 while( !load_script_line(fp) );
762 sprintf(value,"%ld",ftell(fp));
763 script_filesz->update(value);
764 sprintf(value,"%ld",script_line_no);
765 script_lines->update(value);
766 sprintf(value,"%d",script.size());
767 script_entries->update(value);
768 sprintf(value,"%ld",script_text_lines);
769 script_texts->update(value);
770 int hw = 2*script_scroll->get_h();
771 script_scroll->update_length(script.size(), script_entry_no, hw, 0);
772 script_position->update(script_entry_no);
773 script_position->set_boundaries((int64_t)0, (int64_t)script.size()-1);
778 void SWindowGUI::save_spumux_data()
780 char filename[BCTEXTLEN], track_title[BCTEXTLEN];
781 snprintf(filename,sizeof(filename),"%s",script_path);
782 filename[sizeof(filename)-1] = 0;
783 char *bp = strrchr(filename,'/');
784 if( !bp ) bp = filename; else ++bp;
785 char *ext = strrchr(bp, '.');
786 if( !ext ) ext = bp + strlen(bp);
787 int len = sizeof(filename)-1 - (ext-filename);
789 Tracks *tracks = swindow->mwindow->edl->tracks;
790 for( Track *track=tracks->first; track; track=track->next ) {
791 if( track->data_type != TRACK_SUBTITLE ) continue;
792 if( !track->record ) continue;
793 char *cp = track_title;
794 for( char *bp=track->title; *bp; ++bp,++cp )
795 *cp = !isalnum(*bp) ? '_' : *bp;
797 snprintf(ext,len,"-%s.udvd",track_title);
798 FILE *fp = fopen(filename, "w");
800 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
801 SEdit *sedit = (SEdit *)edit;
802 if( sedit->length > 0 ) {
803 int64_t end = start + sedit->length;
804 char *text = sedit->get_text();
806 fprintf(fp, "{%ld}{%ld}%s\n", start, end-1, text);
817 SWindow::SWindow(MWindow *mwindow)
820 this->mwindow = mwindow;
821 window_lock = new Mutex("SWindow::window_lock");
822 swin_lock = new Condition(0,"SWindow::swin_lock");
839 void SWindow::start()
841 if( !Thread::running() ) {
849 if( Thread::running() ) {
852 window_lock->lock("SWindow::stop");
853 if( gui ) gui->stop(1);
854 window_lock->unlock();
862 int root_w = mwindow->gui->get_root_w(1);
863 int root_h = mwindow->gui->get_root_h(1);
869 int x = mwindow->session->swindow_x;
870 int y = mwindow->session->swindow_y;
871 int w = mwindow->session->swindow_w;
872 int h = mwindow->session->swindow_h;
873 if( w < 600 ) w = 600;
874 if( h < 500 ) h = 500;
875 int scr_x = mwindow->gui->get_screen_x(1, -1);
876 int scr_w = mwindow->gui->get_screen_w(1, -1);
877 if( x < scr_x ) x = scr_x;
878 if( x > scr_x+scr_w ) x = scr_x+scr_w;
879 if( x+w > root_w ) x = root_w - w;
880 if( x < 0 ) { x = 0; w = scr_w; }
881 if( y+h > root_h ) y = root_h - h;
882 if( y < 0 ) { y = 0; h = root_h; }
883 if( y+h > root_h ) h = root_h-y;
884 mwindow->session->swindow_x = x;
885 mwindow->session->swindow_y = y;
886 mwindow->session->swindow_w = w;
887 mwindow->session->swindow_h = h;
890 gui = new SWindowGUI(this, x, y, w, h);
891 gui->lock_window("ChannelInfo::gui_create_objects");
892 gui->load_defaults();
893 gui->create_objects();
894 gui->set_icon(mwindow->theme->get_image("record_icon"));
895 gui->reposition_window(x, y);
896 gui->resize_event(w, h);
899 gui->unlock_window();
901 int result = gui->run_window();
903 gui->save_spumux_data();
906 window_lock->lock("ChannelInfo::run 1");
907 gui->save_defaults();
909 window_lock->unlock();
916 void SWindow::run_swin()
918 window_lock->lock("SWindow::run_swin");
920 gui->lock_window("SWindow::run_swin");
922 gui->unlock_window();
926 window_lock->unlock();
929 void SWindow::paste_subttl()
931 window_lock->lock("SWindow::paste_subttl 1");
933 gui->lock_window("SWindow::paste_subttl 2");
934 gui->paste_selection();
935 gui->unlock_window();
937 window_lock->unlock();
940 int SWindow::update_selection()
942 window_lock->lock("SWindow::update_selection 1");
944 gui->lock_window("SWindow::update_selection 2");
945 gui->update_selection();
946 gui->unlock_window();
948 window_lock->unlock();
954 SubttlSWin::SubttlSWin(MWindow *mwindow)
955 : BC_MenuItem(_("SubTitle..."), _("Alt-y"), 'y')
958 this->mwindow = mwindow;
961 SubttlSWin::~SubttlSWin()
965 int SubttlSWin::handle_event()
967 mwindow->gui->swindow->run_swin();