////////////////////////////////////// // Only set script info if it changed int DialogProperties::SetInfoIfDifferent(wxString key,wxString value) { // Get script AssFile *subs = AssFile::top; // Compare if (subs->GetScriptInfo(key) != value) { subs->SetScriptInfo(key,value); return 1; } else return 0; }
/////////////////// // split current line void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) { videoBox->videoDisplay->Stop(); // Get line AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); if (!curline) return; if( !curline->Movement ) return; // Create split lines int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true); int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false); AssFile *subs = AssFile::top; int ResXValue,ResYValue; swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue ); swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue ); int SrcXValue = videoBox->videoDisplay->provider->GetSourceWidth(); int SrcYValue = videoBox->videoDisplay->provider->GetSourceHeight(); float sx = float(ResXValue)/float(SrcXValue); float sy = float(ResYValue)/float(SrcYValue); for( int Frame = StartFrame; Frame < EndFrame; Frame ++ ) { int localframe = Frame - StartFrame; while( curline->Movement->Frames.size() <= localframe ) localframe--; FexMovementFrame f = curline->Movement->Frames[localframe]; // f.Pos.x /= videoBox->videoDisplay->GetW AssDialogue *cur = new AssDialogue( curline->GetEntryData() ); cur->Start.SetMS(VFR_Output.GetTimeAtFrame(Frame,true)); cur->End.SetMS(VFR_Output.GetTimeAtFrame(Frame,false)); cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text; cur->UpdateData(); SubsBox->InsertLine(cur,EditBox->linen + Frame - StartFrame,true,false); } // Remove Movement DeleteMovement( curline->Movement ); curline->Movement = 0; // Remove Tracker delete curline->Tracker; curline->Tracker = 0; // Remove this line SubsBox->DeleteLines(SubsBox->GetRangeArray(EditBox->linen, EditBox->linen)); videoBox->videoDisplay->RefreshVideo(); }
/////////////// // Constructor DialogResample::DialogResample(wxWindow *parent, SubtitlesGrid *_grid) : wxDialog (parent,-1,_("Resample resolution"),wxDefaultPosition) { // Variables AssFile *subs = AssFile::top; grid = _grid; vid = grid->video; // Resolution line wxSizer *ResBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Resolution")); wxSizer *ResSizer = new wxBoxSizer(wxHORIZONTAL); int sw,sh; subs->GetResolution(sw,sh); ResXValue = wxString::Format(_T("%i"),sw); ResYValue = wxString::Format(_T("%i"),sh); ResX = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResXValue)); ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue)); wxStaticText *ResText = new wxStaticText(this,-1,_("x")); wxButton *FromVideo = new wxButton(this,BUTTON_DEST_FROM_VIDEO,_("From video")); if (!vid->loaded) FromVideo->Enable(false); ResSizer->Add(ResX,1,wxRIGHT,5); ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5); ResSizer->Add(ResY,1,wxRIGHT,5); ResSizer->Add(FromVideo,1,0,0); // Resolution box Anamorphic = new wxCheckBox(this,CHECK_ANAMORPHIC,_("Change aspect ratio")); ResBoxSizer->Add(ResSizer,1,wxEXPAND|wxBOTTOM,5); ResBoxSizer->Add(Anamorphic,0,0,0); // Button sizer wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL); ButtonSizer->AddStretchSpacer(1); #ifndef __WXMAC__ ButtonSizer->Add(new wxButton(this,BUTTON_RESAMPLE,_("Resample")),0,wxRIGHT,5); ButtonSizer->Add(new wxButton(this,wxID_CANCEL),0,wxRIGHT,0); #else ButtonSizer->Add(new wxButton(this,wxID_CANCEL),0,wxRIGHT,5); wxButton *resampleButton = new wxButton(this,BUTTON_RESAMPLE,_("Resample")); ButtonSizer->Add(resampleButton,0,wxRight,0); resampleButton->SetDefault(); #endif // Main sizer wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); MainSizer->Add(ResBoxSizer,1,wxEXPAND|wxALL,5); MainSizer->Add(ButtonSizer,0,wxEXPAND|wxRIGHT|wxLEFT|wxBOTTOM,5); MainSizer->SetSizeHints(this); SetSizer(MainSizer); CenterOnParent(); }
/// @brief Load generic subs void AssFile::Load(const wxString &_filename, wxString const& charset) { const SubtitleFormat *reader = SubtitleFormat::GetReader(_filename); try { AssFile temp; reader->ReadFile(&temp, _filename, charset); bool found_style = false; bool found_dialogue = false; // Check if the file has at least one style and at least one dialogue line for (auto const& line : temp.Line) { AssEntryGroup type = line.Group(); if (type == ENTRY_STYLE) found_style = true; if (type == ENTRY_DIALOGUE) found_dialogue = true; if (found_style && found_dialogue) break; } // And if it doesn't add defaults for each if (!found_style) temp.InsertLine(new AssStyle); if (!found_dialogue) temp.InsertLine(new AssDialogue); swap(temp); } catch (agi::UserCancelException const&) { return; } // Set general data loaded = true; filename = _filename; // Add comments and set vars SetScriptInfo("ScriptType", "v4.00+"); // Push the initial state of the file onto the undo stack UndoStack.clear(); RedoStack.clear(); undoDescription.clear(); autosavedCommitId = savedCommitId = commitId + 1; Commit("", COMMIT_NEW); FileOpen(filename); }
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { file.Sort(); StripComments(file); RecombineOverlaps(file); MergeIdentical(file); StripTags(file); ConvertNewlines(file, "\r\n"); // Find last line agi::Time lastTime; if (!file.Events.empty()) lastTime = file.Events.back().End; // Insert blank line at the end auto diag = new AssDialogue; diag->Start = lastTime; diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt(); file.Events.push_back(*diag); }
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { file.Sort(); StripComments(file); RecombineOverlaps(file); MergeIdentical(file); StripTags(file); ConvertNewlines(file, "\r\n"); // Find last line AssTime lastTime; for (auto line : file.Line | boost::adaptors::reversed | agi::of_type<AssDialogue>()) { lastTime = line->End; break; } // Insert blank line at the end auto diag = new AssDialogue; diag->Start = lastTime; diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt(); file.Line.push_back(*diag); }
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { file.Sort(); StripComments(file.Line); RecombineOverlaps(file.Line); MergeIdentical(file.Line); StripTags(file.Line); ConvertNewlines(file.Line, "\r\n"); // Find last line AssTime lastTime; for (LineList::reverse_iterator cur = file.Line.rbegin(); cur != file.Line.rend(); ++cur) { if (AssDialogue *prev = dynamic_cast<AssDialogue*>(*cur)) { lastTime = prev->End; break; } } // Insert blank line at the end AssDialogue *diag = new AssDialogue; diag->Start = lastTime; diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt(); file.Line.push_back(diag); }
void DialogStyleManager::OnCurrentImport() { auto filename = OpenFileSelector(_("Open subtitles file"), "Path/Last/Subtitles", "", "", SubtitleFormat::GetWildcards(0), this); if (filename.empty()) return; std::string charset; try { charset = CharSetDetect::GetEncoding(filename); } catch (agi::UserCancelException const&) { return; } AssFile temp; try { auto reader = SubtitleFormat::GetReader(filename, charset); if (!reader) wxMessageBox("Unsupported subtitle format", "Error", wxOK | wxICON_ERROR | wxCENTER, this); else reader->ReadFile(&temp, filename, charset); } catch (agi::Exception const& err) { wxMessageBox(to_wx(err.GetChainedMessage()), "Error", wxOK | wxICON_ERROR | wxCENTER, this); } catch (...) { wxMessageBox("Unknown error", "Error", wxOK | wxICON_ERROR | wxCENTER, this); return; } // Get styles auto styles = temp.GetStyles(); if (styles.empty()) { wxMessageBox(_("The selected file has no available styles."), _("Error Importing Styles")); return; } // Get selection wxArrayInt selections; int res = GetSelectedChoices(this, selections, _("Choose styles to import:"), _("Import Styles"), to_wx(styles)); if (res == -1 || selections.empty()) return; bool modified = false; // Loop through selection for (auto const& sel : selections) { // Check if there is already a style with that name if (AssStyle *existing = c->ass->GetStyle(styles[sel])) { int answer = wxMessageBox( wxString::Format(_("There is already a style with the name \"%s\" in the current script. Overwrite?"), styles[sel]), _("Style name collision"), wxYES_NO); if (answer == wxYES) { modified = true; *existing = *temp.GetStyle(styles[sel]); } continue; } // Copy modified = true; c->ass->InsertLine(temp.GetStyle(styles[sel])->Clone()); } // Update if (modified) c->ass->Commit(_("style import"), AssFile::COMMIT_STYLES); }
void swap(AssFile &lft, AssFile &rgt) { lft.swap(rgt); }
void AssStyleStorage::ReplaceIntoFile(AssFile &file) { for (auto const& s : style) { delete file.GetStyle(s->name); file.Styles.push_back(*new AssStyle(*s)); } }
//////////// // Resample void DialogResample::OnResample (wxCommandEvent &event) { // Resolutions AssFile *subs = AssFile::top; int x1,y1; subs->GetResolution(x1,y1); long x2 = 0; long y2 = 0; ResX->GetValue().ToLong(&x2); ResY->GetValue().ToLong(&y2); // Check for validity if (x1 == 0 || x2 == 0 || y1 == 0 || y2 == 0) { EndModal(0); return; } // Calculate resamples rx = double(x2)/double(x1); ry = double(y2)/double(y1); r = ry; if (Anamorphic->IsChecked()) ar = rx/ry; else ar = 1.0; // Iterate through subs AssStyle *curStyle; AssDialogue *curDiag; for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { // Apply to dialogues curDiag = AssEntry::GetAsDialogue(*cur); if (curDiag) { try { // Override tags curDiag->ParseASSTags(); curDiag->ProcessParameters(ResampleTags,curDiag); // Drawing tags size_t nblocks = curDiag->Blocks.size(); AssDialogueBlockDrawing *curBlock; for (size_t i=0;i<nblocks;i++) { curBlock = AssDialogueBlock::GetAsDrawing(curDiag->Blocks.at(i)); if (curBlock) { curBlock->MultiplyCoords(rx,ry); } } // Margins curDiag->MarginL = int(curDiag->MarginL * rx + 0.5); curDiag->MarginR = int(curDiag->MarginR * rx + 0.5); curDiag->MarginV = int(curDiag->MarginV * ry + 0.5); // Update curDiag->UpdateText(); curDiag->UpdateData(); curDiag->ClearBlocks(); continue; } catch (const wchar_t *err) { wxLogMessage(err); } catch (wxString err) { wxLogMessage(err); } } // Apply to styles curStyle = AssEntry::GetAsStyle(*cur); if (curStyle) { curStyle->fontsize = int(curStyle->fontsize * r + 0.5); //curStyle->outline_w *= r; //curStyle->shadow_w *= r; curStyle->spacing *= rx; curStyle->scalex *= ar; curStyle->MarginL = int(curStyle->MarginL * rx + 0.5); curStyle->MarginR = int(curStyle->MarginR * rx + 0.5); curStyle->MarginV = int(curStyle->MarginV * ry + 0.5); curStyle->UpdateData(); } } // Change script resolution subs->SetScriptInfo(_T("PlayResX"),wxString::Format(_T("%i"),x2)); subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2)); // Flag as modified subs->FlagAsModified(); grid->CommitChanges();; EndModal(0); }
/////////////// // Constructor DialogProperties::DialogProperties (wxWindow *parent, VideoDisplay *_vid) : wxDialog(parent, -1, _("Script Properties"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { // Setup vid = _vid; AssFile *subs = AssFile::top; // Script details crap wxStaticText *TitleLabel = new wxStaticText(this,-1,_("Title:")); TitleEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Title")),wxDefaultPosition,wxSize(200,20)); wxStaticText *OrigScriptLabel = new wxStaticText(this,-1,_("Original script:")); OrigScriptEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Script")),wxDefaultPosition,wxSize(200,20)); wxStaticText *TranslationLabel = new wxStaticText(this,-1,_("Translation:")); TranslationEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Translation")),wxDefaultPosition,wxSize(200,20)); wxStaticText *EditingLabel = new wxStaticText(this,-1,_("Editing:")); EditingEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Editing")),wxDefaultPosition,wxSize(200,20)); wxStaticText *TimingLabel = new wxStaticText(this,-1,_("Timing:")); TimingEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Timing")),wxDefaultPosition,wxSize(200,20)); wxStaticText *SyncLabel = new wxStaticText(this,-1,_("Synch point:")); SyncEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Synch Point")),wxDefaultPosition,wxSize(200,20)); wxStaticText *UpdatedLabel = new wxStaticText(this,-1,_("Updated by:")); UpdatedEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Script Updated By")),wxDefaultPosition,wxSize(200,20)); wxStaticText *UpdateDetailsLabel = new wxStaticText(this,-1,_("Update details:")); UpdateDetailsEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Update Details")),wxDefaultPosition,wxSize(200,20)); wxSizer *TopSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Script")); wxSizer *TopSizerGrid = new wxFlexGridSizer(0,2,5,5); TopSizerGrid->Add(TitleLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(TitleEdit,1,0,0); TopSizerGrid->Add(OrigScriptLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(OrigScriptEdit,1,0,0); TopSizerGrid->Add(TranslationLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(TranslationEdit,1,0,0); TopSizerGrid->Add(EditingLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(EditingEdit,1,0,0); TopSizerGrid->Add(TimingLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(TimingEdit,1,0,0); TopSizerGrid->Add(SyncLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(SyncEdit,1,0,0); TopSizerGrid->Add(UpdatedLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(UpdatedEdit,1,0,0); TopSizerGrid->Add(UpdateDetailsLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0); TopSizerGrid->Add(UpdateDetailsEdit,1,0,0); TopSizer->Add(TopSizerGrid,0,wxALL,0); // Resolution box wxSizer *ResSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Resolution")); ResXValue = subs->GetScriptInfo(_T("PlayResX")); ResYValue = subs->GetScriptInfo(_T("PlayResY")); ResX = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResXValue)); ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue)); wxStaticText *ResText = new wxStaticText(this,-1,_T("x")); wxButton *FromVideo = new wxButton(this,BUTTON_FROM_VIDEO,_("From video")); if (!vid->loaded) FromVideo->Enable(false); ResSizer->Add(ResX,1,wxRIGHT,5); ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5); ResSizer->Add(ResY,1,wxRIGHT,5); ResSizer->Add(FromVideo,1,0,0); // Wrap box wxSizer *WrapBox = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Wrap style")); wxArrayString options; options.Add(_("0: Smart wrapping, top line is wider")); options.Add(_("1: End-of-line word wrapping, only \\N breaks")); options.Add(_("2: No word wrapping, both \\n and \\N break")); options.Add(_("3: Smart wrapping, bottom line is wider")); WrapStyle = new wxComboBox(this,-1,_T(""),wxDefaultPosition,wxDefaultSize,options,wxCB_READONLY); long n; subs->GetScriptInfo(_T("WrapStyle")).ToLong(&n); WrapStyle->SetSelection(n); WrapBox->Add(WrapStyle,1,0,0); // Button sizer wxButton *ButtonOK = new wxButton(this,wxID_OK); ButtonOK->SetDefault(); wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL); ButtonSizer->AddStretchSpacer(1); ButtonSizer->Add(ButtonOK,0,0,0); // MainSizer wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); MainSizer->Add(TopSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5); MainSizer->Add(ResSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5); MainSizer->Add(WrapBox,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5); MainSizer->Add(ButtonSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5); // Set sizer SetSizer(MainSizer); MainSizer->SetSizeHints(this); CenterOnParent(); }
void SubsController::Load(agi::fs::path const& filename, std::string charset) { try { if (charset.empty()) charset = CharSetDetect::GetEncoding(filename); } catch (agi::UserCancelException const&) { return; } // Make sure that file isn't actually a timecode file if (charset != "binary") { try { TextFileReader testSubs(filename, charset); std::string cur = testSubs.ReadLineFromFile(); if (boost::starts_with(cur, "# timecode")) { context->videoController->LoadTimecodes(filename); return; } } catch (...) { // if trying to load the file as timecodes fails it's fairly // safe to assume that it is in fact not a timecode file } } const SubtitleFormat *reader = SubtitleFormat::GetReader(filename); try { AssFile temp; reader->ReadFile(&temp, filename, charset); bool found_style = false; bool found_dialogue = false; // Check if the file has at least one style and at least one dialogue line for (auto const& line : temp.Line) { AssEntryGroup type = line.Group(); if (type == AssEntryGroup::STYLE) found_style = true; if (type == AssEntryGroup::DIALOGUE) found_dialogue = true; if (found_style && found_dialogue) break; } // And if it doesn't add defaults for each if (!found_style) temp.InsertLine(new AssStyle); if (!found_dialogue) temp.InsertLine(new AssDialogue); context->ass->swap(temp); } catch (agi::UserCancelException const&) { return; } catch (agi::fs::FileNotFound const&) { wxMessageBox(filename.wstring() + " not found.", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent); config::mru->Remove("Subtitle", filename); return; } catch (agi::Exception const& err) { wxMessageBox(to_wx(err.GetChainedMessage()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent); return; } catch (std::exception const& err) { wxMessageBox(to_wx(err.what()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent); return; } catch (...) { wxMessageBox("Unknown error", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent); return; } SetFileName(filename); // Push the initial state of the file onto the undo stack undo_stack.clear(); redo_stack.clear(); autosaved_commit_id = saved_commit_id = commit_id + 1; context->ass->Commit("", AssFile::COMMIT_NEW); // Save backup of file if (CanSave() && OPT_GET("App/Auto/Backup")->GetBool()) { auto path_str = OPT_GET("Path/Auto/Backup")->GetString(); agi::fs::path path; if (path_str.empty()) path = filename.parent_path(); else path = config::path->Decode(path_str); agi::fs::CreateDirectory(path); agi::fs::Copy(filename, path/(filename.stem().string() + ".ORIGINAL" + filename.extension().string())); } FileOpen(filename); }