/// @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); }
////////////// // 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(); }
////////////////////////////// // 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(); }