/////////////////// // 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(); }
/////////////////// // link line to move file void FrameMain::OnVideoTrackLinkFile(wxCommandEvent &event) { videoBox->videoDisplay->Stop(); // Get line AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); if (!curline) return; wxString link = wxGetTextFromUser(_("Link name:"), _("Link line to movement file"), curline->Movement?curline->Movement->FileName:_T(""), this); if( link.empty() ) curline->Effect = _T(""); else curline->Effect = _T("FexMovement:")+link; curline->UpdateData(); if( !curline->Effect.empty() && curline->Movement ) SaveMovement( curline->Movement, curline->Effect.AfterFirst(':').c_str() ); }
void SubtitlesGrid::CopyLines(wxArrayInt target) { // Prepare text wxString data; AssDialogue *cur; int nrows = target.Count(); bool first = true; for (int i=0;i<nrows;i++) { if (!first) data += "\r\n"; first = false; cur = GetDialogue(target[i]); data += cur->GetEntryData(); } // Send to clipboard if (wxTheClipboard->Open()) { wxTheClipboard->SetData(new wxTextDataObject(data)); wxTheClipboard->Close(); } }
///////////////////////////// // Set style of current line void DialogStyling::SetStyle (wxString curName, bool jump) { // Get line AssDialogue *line = grid->GetDialogue(linen); // Update line line->Style = curName; line->UpdateData(); // Update grid/subs grid->Refresh(false); if (PreviewCheck->IsChecked()) { grid->ass->FlagAsModified(_("Change Style (Assistant)")); grid->CommitChanges(); } else needCommit = true; // Next line if (jump) JumpToLine(linen+1); }
/////////////////////// // Transform framerate void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { int n=0; // Run through using std::list; AssEntry *curEntry; AssDialogue *curDialogue; for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { curEntry = *cur; curEntry->StartMS = Input->GetTimeAtFrame(Output->GetFrameAtTime(curEntry->StartMS,true),true); curDialogue = AssEntry::GetAsDialogue(curEntry); // Update dialogue entries if (curDialogue) { // Line data LineData data; data.line = curDialogue; data.k = 0; data.kf = 0; data.ko = 0; // Process stuff curDialogue->ParseASSTags(); curDialogue->ProcessParameters(TransformTimeTags,&data); curDialogue->Start.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->Start.GetMS(),true),true)); curDialogue->End.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->End.GetMS(),false),false)); curDialogue->UpdateText(); curDialogue->UpdateData(); curDialogue->ClearBlocks(); n++; } } }
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { if (!Input->IsLoaded() || !Output->IsLoaded()) return; for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur); if (curDialogue) { line = curDialogue; newK = 0; oldK = 0; newStart = trunc_cs(ConvertTime(curDialogue->Start)); newEnd = trunc_cs(ConvertTime(curDialogue->End) + 9); // Process stuff curDialogue->ParseASSTags(); curDialogue->ProcessParameters(TransformTimeTags, this); curDialogue->Start = newStart; curDialogue->End = newEnd; curDialogue->UpdateText(); curDialogue->ClearBlocks(); } } }
/////////// // Collect void FontsCollectorThread::Collect() { // Make sure there is a separator at the end destination += _T("\\"); // Reset log box wxTextCtrl *LogBox = collector->LogBox; wxMutexGuiEnter(); LogBox->SetValue(_T("")); LogBox->SetDefaultStyle(wxTextAttr(wxColour(0,0,180))); LogBox->AppendText(_("Searching for fonts in file...\n")); LogBox->SetDefaultStyle(wxTextAttr(wxColour(0,0,0))); LogBox->Refresh(); LogBox->Update(); wxSafeYield(); wxMutexGuiLeave(); // Scans file bool fileModified = false; AssStyle *curStyle; AssDialogue *curDiag; curLine = 0; for (std::list<AssEntry*>::iterator cur=subs->Line.begin();cur!=subs->Line.end();cur++) { // Collect from style curStyle = AssEntry::GetAsStyle(*cur); if (curStyle) { AddFont(curStyle->font,true); wxMutexGuiEnter(); LogBox->AppendText(wxString(_T("\"")) + curStyle->font + _("\" found on style \"") + curStyle->name + _T("\".\n")); LogBox->Refresh(); LogBox->Update(); wxSafeYield(); wxMutexGuiLeave(); } // Collect from dialogue else { curDiag = AssEntry::GetAsDialogue(*cur); if (curDiag) { curLine++; curDiag->ParseASSTags(); curDiag->ProcessParameters(GetFonts); curDiag->ClearBlocks(); } } } #ifdef __WINDOWS__ // Collect font data wxMutexGuiEnter(); LogBox->SetDefaultStyle(wxTextAttr(wxColour(0,0,180))); LogBox->AppendText(_("\nReading fonts from registry...\n")); LogBox->SetDefaultStyle(wxTextAttr(wxColour(0,0,0))); wxSafeYield(); wxMutexGuiLeave(); CollectFontData(); // Get fonts folder wxString source; TCHAR szPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS,NULL,0,szPath))) { source = wxString(szPath); } else source = wxGetOSDirectory() + _T("\\fonts"); source += _T("\\"); // Get font file names wxArrayString work; wxArrayString copied; bool attaching = collector->AttachmentCheck->IsChecked(); for (size_t i=0;i<fonts.GetCount();i++) { try { work = GetFontFiles(fonts[i]); for (size_t j=0;j<work.GetCount();j++) { // Get path to font file wxString srcFile,dstFile; wxFileName srcFileName(work[j]); if (srcFileName.FileExists() && srcFileName.IsAbsolute()) { srcFile = work[j]; dstFile = destination + srcFileName.GetFullName(); } else { srcFile = source + work[j]; dstFile = destination + work[j]; } if (copied.Index(work[j]) == wxNOT_FOUND) { copied.Add(work[j]); // Check if it exists if (!attaching && wxFileName::FileExists(dstFile)) { wxMutexGuiEnter(); LogBox->SetDefaultStyle(wxTextAttr(wxColour(255,128,0))); LogBox->AppendText(wxString(_T("\"")) + work[j] + _("\" already exists on destination.\n")); LogBox->Refresh(); LogBox->Update(); wxSafeYield(); wxMutexGuiLeave(); } // Copy else { // Copy font bool success; if (attaching) { try { subs->InsertAttachment(srcFile); fileModified = true; success = true; } catch (...) { success = false; } } else success = Copy(srcFile,dstFile); // Report wxMutexGuiEnter(); if (success) { LogBox->SetDefaultStyle(wxTextAttr(wxColour(0,180,0))); LogBox->AppendText(wxString(_T("\"")) + work[j] + _("\" copied.\n")); } else { LogBox->SetDefaultStyle(wxTextAttr(wxColour(220,0,0))); LogBox->AppendText(wxString(_("Failed copying \"")) + srcFile + _T("\".\n")); } LogBox->Refresh(); LogBox->Update(); wxSafeYield(); wxMutexGuiLeave(); } } } } catch (...) { wxMutexGuiEnter(); LogBox->SetDefaultStyle(wxTextAttr(wxColour(220,0,0))); LogBox->AppendText(wxString(_("Could not find font ")) + fonts[i] + _T("\n")); wxMutexGuiLeave(); } } #endif // Flag file as modified if (fileModified) { subs->FlagAsModified(); collector->main->SubsBox->CommitChanges(); } }
void TXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { size_t num_actor_names = 0, num_dialogue_lines = 0; // Detect number of lines with Actor field filled out for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); if (dia && !dia->Comment) { num_dialogue_lines++; if (!dia->Actor.empty()) num_actor_names++; } } // If too few lines have Actor filled out, don't write it bool write_actors = num_actor_names > num_dialogue_lines/2; bool strip_formatting = true; TextFileWriter file(filename, encoding); file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString()); // Write the file for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); if (dia) { wxString out_line; if (dia->Comment) { out_line = "# "; } if (write_actors) { out_line += dia->Actor + ": "; } wxString out_text; if (strip_formatting) { dia->ParseASSTags(); for (std::vector<AssDialogueBlock*>::iterator block = dia->Blocks.begin(); block != dia->Blocks.end(); ++block) { if ((*block)->GetType() == BLOCK_PLAIN) { out_text += (*block)->GetText(); } } dia->ClearBlocks(); } else { out_text = dia->Text; } out_line += out_text; if (!out_text.empty()) { file.WriteLineToFile(out_line); } } else { // Not a dialogue line // TODO: should any non-dia lines cause blank lines in output? //file.WriteLineToFile(""); } } }
//////////// // 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); }
////////////// // Draw image void BaseGrid::DrawImage(wxDC &dc) { dc.BeginDrawing(); // Get size and pos int w = 0; int h = 0; GetClientSize(&w,&h); // Set font dc.SetFont(font); // Clear background dc.SetBackground(wxBrush(Options.AsColour(_T("Grid Background")))); dc.Clear(); // Draw labels dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(Options.AsColour(_T("Grid left column")))); dc.DrawRectangle(0,lineHeight,colWidth[0],h-lineHeight); // Visible lines int drawPerScreen = h/lineHeight + 1; int nDraw = MID(0,drawPerScreen,GetRows()-yPos); int maxH = (nDraw+1) * lineHeight; // Row colors std::vector<wxBrush> rowColors; std::vector<wxColor> foreColors; rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Background")))); // 0 = Standard foreColors.push_back(Options.AsColour(_T("Grid standard foreground"))); rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Header")))); // 1 = Header foreColors.push_back(Options.AsColour(_T("Grid standard foreground"))); rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selection background")))); // 2 = Selected foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); rowColors.push_back(wxBrush(Options.AsColour(_T("Grid comment background")))); // 3 = Commented foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); rowColors.push_back(wxBrush(Options.AsColour(_T("Grid inframe background")))); // 4 = Video Highlighted foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selected comment background")))); // 5 = Commented & selected foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); // First grid row bool drawGrid = true; if (drawGrid) { dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); dc.DrawLine(0,0,w,0); dc.SetPen(*wxTRANSPARENT_PEN); } // Draw rows int dx = 0; int dy = 0; int curColor = 0; AssDialogue *curDiag; for (int i=0;i<nDraw+1;i++) { // Prepare int curRow = i+yPos-1; curDiag = GetDialogue(curRow); dx = 0; dy = i*lineHeight; // Check for collisions bool collides = false; if (curDiag) { AssDialogue *sel = GetDialogue(editBox->linen); if (sel && sel != curDiag) { if (curDiag->CollidesWith(sel)) collides = true; } } // Text array wxArrayString strings; // Header if (i == 0) { strings.Add(_("#")); strings.Add(_("L")); strings.Add(_("Start")); strings.Add(_("End")); strings.Add(_("Style")); strings.Add(_("Actor")); strings.Add(_("Effect")); strings.Add(_("Left")); strings.Add(_("Right")); strings.Add(_("Vert")); strings.Add(_("Text")); curColor = 1; } // Lines else if (curDiag) { // Set fields strings.Add(wxString::Format(_T("%i"),curRow+1)); strings.Add(wxString::Format(_T("%i"),curDiag->Layer)); if (byFrame) { strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true))); strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),true))); } else { strings.Add(curDiag->Start.GetASSFormated()); strings.Add(curDiag->End.GetASSFormated()); } strings.Add(curDiag->Style); strings.Add(curDiag->Actor); strings.Add(curDiag->Effect); strings.Add(curDiag->GetMarginString(1)); strings.Add(curDiag->GetMarginString(2)); strings.Add(curDiag->GetMarginString(3)); // Set text int mode = Options.AsInt(_T("Grid Hide Overrides")); wxString value = _T(""); // Hidden overrides if (mode == 1 || mode == 2) { wxString replaceWith = Options.AsText(_T("Grid hide overrides char")); curDiag->ParseASSTags(); size_t n = curDiag->Blocks.size(); for (size_t i=0;i<n;i++) { AssDialogueBlock *block = curDiag->Blocks.at(i); AssDialogueBlockPlain *plain = AssDialogueBlock::GetAsPlain(block); if (plain) { value += plain->GetText(); } else { if (mode == 1) { value += replaceWith; } } } curDiag->ClearBlocks(); } // Show overrides else value = curDiag->Text; // Cap length and set text if (value.Length() > 512) value = value.Left(512) + _T("..."); strings.Add(value); // Set color curColor = 0; bool inSel = IsInSelection(curRow,0); if (inSel && curDiag->Comment) curColor = 5; else if (inSel) curColor = 2; else if (curDiag->Comment) curColor = 3; else if (Options.AsBool(_T("Highlight subs in frame")) && IsDisplayed(curDiag)) curColor = 4; } else { for (int j=0;j<11;j++) strings.Add(_T("?")); } // Draw row background color if (curColor) { dc.SetBrush(rowColors[curColor]); dc.DrawRectangle((curColor == 1) ? 0 : colWidth[0],i*lineHeight+1,w,lineHeight); } // Set text color if (collides) dc.SetTextForeground(Options.AsColour(_T("Grid collision foreground"))); else { dc.SetTextForeground(foreColors[curColor]); } // Draw text wxRect cur; bool isCenter; for (int j=0;j<11;j++) { // Is center? isCenter = !(j == 4 || j == 5 || j == 6 || j == 10); // Calculate clipping cur = wxRect(dx+4,dy,colWidth[j]-6,lineHeight); // Set clipping dc.DestroyClippingRegion(); dc.SetClippingRegion(cur); // Draw dc.DrawLabel(strings[j],cur,isCenter ? wxALIGN_CENTER : (wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT)); dx += colWidth[j]; } //if (collides) dc.SetPen(wxPen(wxColour(255,0,0))); // Draw grid dc.DestroyClippingRegion(); if (drawGrid) { dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); dc.DrawLine(0,dy+lineHeight,w,dy+lineHeight); dc.SetPen(*wxTRANSPARENT_PEN); } } // Draw grid columns dx = 0; if (drawGrid) { dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); for (int i=0;i<10;i++) { dx += colWidth[i]; dc.DrawLine(dx,0,dx,maxH); } dc.DrawLine(0,0,0,maxH); dc.DrawLine(w-1,0,w-1,h); } // Draw currently active line border dc.SetPen(wxPen(Options.AsColour(_T("Grid Active border")))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dy = (editBox->linen+1-yPos) * lineHeight; dc.DrawRectangle(0,dy,w,lineHeight+1); // Done dc.EndDrawing(); }
//////////////////////////////// // Find & Replace next instance void SearchReplaceEngine::ReplaceNext(bool DoReplace) { // Check if it's OK to go on if (!CanContinue) { OpenDialog(DoReplace); return; } wxArrayInt sels = grid->GetSelection(); // if selection has changed reset values if (sels[0] < curLine) { curLine = sels[0]; Modified = false; LastWasFind = true; pos = 0; matchLen = 0; replaceLen = 0; } // Setup int start = curLine; int nrows = grid->GetRows(); bool found = false; wxString *Text; size_t tempPos; int regFlags = wxRE_ADVANCED; if (!matchCase) { if (isReg) regFlags |= wxRE_ICASE; else LookFor.MakeLower(); } // Search for it while (!found) { Text = GetText(curLine,field); if (DoReplace && LastWasFind) tempPos = pos; else tempPos = pos+replaceLen; // RegExp if (isReg) { wxRegEx regex (LookFor,regFlags); if (regex.IsValid()) { if (regex.Matches(Text->Mid(tempPos))) { size_t match_start; regex.GetMatch(&match_start,&matchLen,0); pos = match_start + tempPos; //matchLen++; found = true; } } } // Normal else { wxString src = Text->Mid(tempPos); if (!matchCase) src.MakeLower(); pos = src.Find(LookFor); if (pos != -1) { pos += tempPos; found = true; matchLen = LookFor.Length(); } } // Didn't find, go to next line if (!found) { curLine++; pos = 0; matchLen = 0; replaceLen = 0; if (curLine == nrows) curLine = 0; if (curLine == start) break; } } // Found if (found) { grid->BeginBatch(); // If replacing if (DoReplace) { // Replace with regular expressions if (isReg) { wxString toReplace = Text->Mid(pos,matchLen); wxRegEx regex(LookFor,regFlags); regex.ReplaceFirst(&toReplace,ReplaceWith); *Text = Text->Left(pos) + toReplace + Text->Mid(pos+matchLen); replaceLen = toReplace.Length(); } // Normal replace else { *Text = Text->Left(pos) + ReplaceWith + Text->Mid(pos+matchLen); replaceLen = ReplaceWith.Length(); } // Update AssDialogue *cur = grid->GetDialogue(curLine); //cur->ParseASSTags(); cur->UpdateData(); // Commit grid->ass->FlagAsModified(); } else { replaceLen = matchLen; } // Select grid->SelectRow(curLine,false); grid->MakeCellVisible(curLine,0); if (field == 0) { grid->editBox->SetToLine(curLine); grid->editBox->TextEdit->SetSelectionU(pos,pos+replaceLen); } grid->EndBatch(); // Update video if (updateVideo) { grid->CommitChanges(); grid->SetVideoToSubs(true); } else if (DoReplace) Modified = true; // hAx to prevent double match on style/actor if (field != 0) replaceLen = 99999; } LastWasFind = !DoReplace; }
/// @brief Actually process subtitles /// void DialogTimingProcessor::Process() { SortDialogues(); int rows = Sorted.size(); // Options long inVal = 0; long outVal = 0; leadIn->GetValue().ToLong(&inVal); leadOut->GetValue().ToLong(&outVal); bool addIn = hasLeadIn->IsChecked() && inVal; bool addOut = hasLeadOut->IsChecked() && outVal; // Add lead-in/out if (addIn || addOut) { for (int i=0; i<rows; i++) { AssDialogue *cur = Sorted[i]; // Compare to every previous line (yay for O(n^2)!) to see if it's OK to add lead-in if (inVal) { int startLead = cur->Start.GetMS() - inVal; for (int j=0; j<i; j++) { AssDialogue *comp = Sorted[j]; // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times startLead = std::max(startLead, comp->End.GetMS()); } cur->Start.SetMS(startLead); } // Compare to every line to see how far can lead-out be extended if (outVal) { int endLead = cur->End.GetMS() + outVal; for (int j=i+1; j<rows; j++) { AssDialogue *comp = Sorted[j]; // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times endLead = std::min(endLead, comp->Start.GetMS()); } cur->End.SetMS(endLead); } } } // Make adjacent if (adjsEnable->IsChecked()) { AssDialogue *prev = Sorted.front(); long adjsThres = 0; adjacentThres->GetValue().ToLong(&adjsThres); float bias = adjacentBias->GetValue() / 100.0; for (int i=1; i < rows; i++) { AssDialogue *cur = Sorted[i]; // Check if they don't collide if (cur->CollidesWith(prev)) continue; // Compare distance int curStart = cur->Start.GetMS(); int prevEnd = prev->End.GetMS(); int dist = curStart-prevEnd; if (dist > 0 && dist < adjsThres) { int setPos = prevEnd+int(dist*bias); cur->Start.SetMS(setPos); prev->End.SetMS(setPos); } prev = cur; } } // Keyframe snapping if (keysEnable->IsChecked()) { KeyFrames = c->videoController->GetKeyFrames(); KeyFrames.push_back(c->videoController->GetLength() - 1); long beforeStart = 0; long afterStart = 0; long beforeEnd = 0; long afterEnd = 0; keysStartBefore->GetValue().ToLong(&beforeStart); keysStartAfter->GetValue().ToLong(&afterStart); keysEndBefore->GetValue().ToLong(&beforeEnd); keysEndAfter->GetValue().ToLong(&afterEnd); for (int i=0; i<rows; i++) { AssDialogue *cur = Sorted[i]; // Get start/end frames int startF = c->videoController->FrameAtTime(cur->Start.GetMS(),agi::vfr::START); int endF = c->videoController->FrameAtTime(cur->End.GetMS(),agi::vfr::END); // Get closest for start int closest = GetClosestKeyFrame(startF); if ((closest > startF && closest-startF <= beforeStart) || (closest < startF && startF-closest <= afterStart)) { cur->Start.SetMS(c->videoController->TimeAtFrame(closest,agi::vfr::START)); } // Get closest for end closest = GetClosestKeyFrame(endF)-1; if ((closest > endF && closest-endF <= beforeEnd) || (closest < endF && endF-closest <= afterEnd)) { cur->End.SetMS(c->videoController->TimeAtFrame(closest,agi::vfr::END)); } } } // Update grid c->ass->Commit(_("timing processor"), AssFile::COMMIT_TIMES); }
///////////// // Read file void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std; // Reader TextFileReader file(filename,encoding,false); // Default LoadDefault(false); // Data wxString actor; wxString separator = Options.AsText(_T("Text actor separator")); wxString comment = Options.AsText(_T("Text comment starter")); bool isComment = false; int lines = 0; // Parse file AssDialogue *line = NULL; while (file.HasMoreLines()) { // Reads line wxString value = file.ReadLineFromFile(); // Check if this isn't a timecodes file if (value.Left(10) == _T("# timecode")) { throw _T("File is a timecode file, cannot load as subtitles."); } // Read comment data isComment = false; if (comment != _T("") && value.Left(comment.Length()) == comment) { isComment = true; value = value.Mid(comment.Length()); } // Read actor data if (!isComment && separator != _T("")) { if (value[0] != _T(' ') && value[0] != _T('\t')) { int pos = value.Find(separator); if (pos != wxNOT_FOUND) { actor = value.Left(pos); actor.Trim(false); actor.Trim(true); value = value.Mid(pos+1); value.Trim(false); } } } // Trim spaces at start value.Trim(false); // Sets line up line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); if (isComment) line->Actor = _T(""); else line->Actor = actor; if (value.IsEmpty()) { line->Actor = _T(""); isComment = true; } line->Comment = isComment; line->Text = value; line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(0); line->UpdateData(); //line->ParseASSTags(); // Adds line Line->push_back(line); lines++; } // No lines? if (lines == 0) { AssDialogue *line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(5000); Line->push_back(line); } }
///////////// // Write file void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using namespace std; size_t num_actor_names = 0, num_dialogue_lines = 0; // Detect number of lines with Actor field filled out for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) { AssDialogue *dia = AssEntry::GetAsDialogue(*l); if (dia && !dia->Comment) { num_dialogue_lines++; if (!dia->Actor.IsEmpty()) num_actor_names++; } } // If too few lines have Actor filled out, don't write it bool write_actors = num_actor_names > num_dialogue_lines/2; bool strip_formatting = true; TextFileWriter file(filename, encoding); file.WriteLineToFile(_T("# Exported by Aegisub ") + GetAegisubShortVersionString()); // Write the file for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) { AssDialogue *dia = AssEntry::GetAsDialogue(*l); if (dia) { wxString out_line; if (dia->Comment) { out_line = _T("# "); } if (write_actors) { out_line += dia->Actor + _T(": "); } wxString out_text; if (strip_formatting) { dia->ParseASSTags(); for (std::vector<AssDialogueBlock*>::iterator block = dia->Blocks.begin(); block != dia->Blocks.end(); ++block) { if ((*block)->type == BLOCK_PLAIN) { out_text += (*block)->GetText(); } } dia->ClearBlocks(); } else { out_text = dia->Text; } out_line += out_text; if (!out_text.IsEmpty()) { file.WriteLineToFile(out_line); } } else { // Not a dialogue line // TODO: should any non-dia lines cause blank lines in output? //file.WriteLineToFile(_T("")); } } }
///////////////////////// // Replace all instances void SearchReplaceEngine::ReplaceAll() { // Setup wxString *Text; int nrows = grid->GetRows(); size_t count = 0; int regFlags = wxRE_ADVANCED; if (!matchCase) { if (isReg) regFlags |= wxRE_ICASE; //else LookFor.MakeLower(); } bool replaced; grid->BeginBatch(); // Selection bool hasSelection = false; wxArrayInt sels = grid->GetSelection(); if (sels.Count() > 0) hasSelection = true; bool inSel = false; if (affect == 1) inSel = true; // Scan for (int i=0;i<nrows;i++) { // Check if row is selected if (inSel && hasSelection && sels.Index(i) == wxNOT_FOUND) { continue; } // Prepare replaced = false; Text = GetText(i,field); // Regular expressions if (isReg) { wxRegEx reg(LookFor,regFlags); if (reg.IsValid()) { size_t reps = reg.ReplaceAll(Text,ReplaceWith); if (reps > 0) replaced = true; count += reps; } } // Normal replace else { if (Text->Contains(LookFor)) { count += Text->Replace(LookFor,ReplaceWith); replaced = true; } } // Replaced? if (replaced) { AssDialogue *cur = grid->GetDialogue(i); cur->UpdateData(); //cur->ParseASSTags(); } } // Commit if (count > 0) { grid->ass->FlagAsModified(); grid->CommitChanges(); wxMessageBox(wxString::Format(_("%i matches were replaced."),count)); } // None found else { wxMessageBox(_("No matches found.")); } grid->EndBatch(); LastWasFind = false; }
///////////// // Read file void SRTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std; // Reader TextFileReader file(filename,encoding); // Default LoadDefault(false); // Parse file int linen = 1; int fileLine = 0; int mode = 0; int lines = 0; long templ; AssDialogue *line = NULL; while (file.HasMoreLines()) { // Reads line wxString curLine = file.ReadLineFromFile(); fileLine++; switch (mode) { case 0: // Checks if there is anything to read if (curLine.IsEmpty()) continue; // Check if it's a line number if (!curLine.IsNumber()) { Clear(); throw wxString::Format(_T("Parse error on entry %i at line %i (expecting line number). Possible malformed file."),linen,fileLine); } // Read line number curLine.ToLong(&templ); if (templ != linen) { linen = templ; } line = new AssDialogue(); mode = 1; break; case 1: // Read timestamps if (curLine.substr(13,3) != _T("-->")) { Clear(); throw wxString::Format(_T("Parse error on entry %i at line %i (expecting timestamps). Possible malformed file."),linen,fileLine); } line->Start.ParseSRT(curLine.substr(0,12)); line->End.ParseSRT(curLine.substr(17,12)); mode = 2; break; case 2: // Checks if it's done if (curLine.IsEmpty() || !file.HasMoreLines()) { mode = 0; linen++; line->group = _T("[Events]"); line->Style = _T("Default"); line->Comment = false; line->UpdateData(); line->ParseSRTTags(); line->StartMS = line->Start.GetMS(); Line->push_back(line); lines++; break; } // Append text if (line->Text != _T("")) line->Text += _T("\\N"); line->Text += curLine; break; } } // No lines? if (lines == 0) { AssDialogue *line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(5000); Line->push_back(line); } }
////////////////////////////// // Actually process subtitles void DialogTimingProcessor::Process() { // Sort rows SortDialogues(); int rows = Sorted.size(); // Options long inVal = 0; long outVal = 0; leadIn->GetValue().ToLong(&inVal); leadOut->GetValue().ToLong(&outVal); bool addIn = hasLeadIn->IsChecked() && inVal; bool addOut = hasLeadOut->IsChecked() && outVal; // Add lead-in/out if (addIn || addOut) { // Variables AssDialogue *cur; AssDialogue *comp; int start,end; int startLead,endLead; int compStart,compEnd; // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Set variables start = cur->Start.GetMS(); end = cur->End.GetMS(); if (addIn) startLead = start - inVal; else startLead = start; if (addOut) endLead = end + outVal; else endLead = end; // Compare to every previous line (yay for O(n^2)!) to see if it's OK to add lead-in if (addIn) { for (int j=0;j<i;j++) { comp = GetSortedDialogue(j); // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times compEnd = comp->End.GetMS(); // Limit lead-in if needed if (compEnd > startLead) startLead = compEnd; } } // Compare to every line to see how far can lead-out be extended if (addOut) { for (int j=i+1;j<rows;j++) { comp = GetSortedDialogue(j); // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times compStart = comp->Start.GetMS(); // Limit lead-in if needed if (compStart < endLead) endLead = compStart; } } // Set times cur->Start.SetMS(startLead); cur->End.SetMS(endLead); cur->UpdateData(); } } // Make adjascent if (adjsEnable->IsChecked()) { // Variables AssDialogue *cur; AssDialogue *prev = NULL; int curStart,prevEnd; long adjsThres = 0; int dist; // Get threshold adjascentThres->GetValue().ToLong(&adjsThres); // Get bias float bias = adjascentBias->GetValue() / 100.0; // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Check if previous is OK if (!prev) { prev = cur; continue; } // Check if they don't collide if (cur->CollidesWith(prev)) continue; // Compare distance curStart = cur->Start.GetMS(); prevEnd = prev->End.GetMS(); dist = curStart-prevEnd; if (dist > 0 && dist < adjsThres) { int setPos = prevEnd+int(dist*bias); cur->Start.SetMS(setPos); cur->UpdateData(); prev->End.SetMS(setPos); prev->UpdateData(); } // Set previous prev = cur; } } // Keyframe snapping if (keysEnable->IsChecked()) { // Get keyframes KeyFrames = grid->video->KeyFrames; KeyFrames.Add(grid->video->length-1); // Variables int startF,endF; int closest; bool changed; AssDialogue *cur; // Get variables long beforeStart = 0; long afterStart = 0; long beforeEnd = 0; long afterEnd = 0; keysStartBefore->GetValue().ToLong(&beforeStart); keysStartAfter->GetValue().ToLong(&afterStart); keysEndBefore->GetValue().ToLong(&beforeEnd); keysEndAfter->GetValue().ToLong(&afterEnd); // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Get start/end frames startF = VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true); endF = VFR_Output.GetFrameAtTime(cur->End.GetMS(),false); changed = false; // Get closest for start closest = GetClosestKeyFrame(startF); if ((closest > startF && closest-startF <= beforeStart) || (closest < startF && startF-closest <= afterStart)) { cur->Start.SetMS(VFR_Output.GetTimeAtFrame(closest,true)); changed = true; } // Get closest for end closest = GetClosestKeyFrame(endF)-1; if ((closest > endF && closest-endF <= beforeEnd) || (closest < endF && endF-closest <= afterEnd)) { cur->End.SetMS(VFR_Output.GetTimeAtFrame(closest,false)); changed = true; } // Apply changes if (changed) { cur->UpdateData(); } } } // Update grid grid->ass->FlagAsModified(); grid->CommitChanges(); }