Merge pull request #7931 from Flitskikker/feature/btc-improvements-20240205

Some "Beautify time codes" improvements
This commit is contained in:
Nikolaj Olsson 2024-02-17 07:51:10 +01:00 committed by GitHub
commit 386a1047ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 677 additions and 39 deletions

View File

@ -2979,15 +2979,19 @@ $HorzAlign = Center
public int ChainingGeneralMaxGap { get; set; }
public int ChainingGeneralLeftGreenZone { get; set; }
public int ChainingGeneralLeftRedZone { get; set; }
public ChainingGeneralShotChangeBehaviorEnum ChainingGeneralShotChangeBehavior { get; set; }
public ChainingShotChangeBehaviorEnum ChainingGeneralShotChangeBehavior { get; set; }
public bool ChainingInCueOnShotUseZones { get; set; }
public int ChainingInCueOnShotMaxGap { get; set; }
public int ChainingInCueOnShotLeftGreenZone { get; set; }
public int ChainingInCueOnShotLeftRedZone { get; set; }
public ChainingShotChangeBehaviorEnum ChainingInCueOnShotShotChangeBehavior { get; set; }
public bool ChainingInCueOnShotCheckGeneral { get; set; }
public bool ChainingOutCueOnShotUseZones { get; set; }
public int ChainingOutCueOnShotMaxGap { get; set; }
public int ChainingOutCueOnShotRightRedZone { get; set; }
public int ChainingOutCueOnShotRightGreenZone { get; set; }
public ChainingShotChangeBehaviorEnum ChainingOutCueOnShotShotChangeBehavior { get; set; }
public bool ChainingOutCueOnShotCheckGeneral { get; set; }
public enum Preset : int
{
@ -2996,7 +3000,7 @@ $HorzAlign = Center
SDI = 2,
}
public enum ChainingGeneralShotChangeBehaviorEnum : int
public enum ChainingShotChangeBehaviorEnum : int
{
DontChain = 0,
ExtendCrossingShotChange = 1,
@ -3036,15 +3040,19 @@ $HorzAlign = Center
ChainingGeneralMaxGap = 500;
ChainingGeneralLeftGreenZone = 12;
ChainingGeneralLeftRedZone = 11;
ChainingGeneralShotChangeBehavior = ChainingGeneralShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingGeneralShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingInCueOnShotUseZones = false;
ChainingInCueOnShotMaxGap = 500;
ChainingInCueOnShotLeftGreenZone = 12;
ChainingInCueOnShotLeftRedZone = 11;
ChainingInCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingInCueOnShotCheckGeneral = true;
ChainingOutCueOnShotUseZones = false;
ChainingOutCueOnShotMaxGap = 500;
ChainingOutCueOnShotRightRedZone = 11;
ChainingOutCueOnShotRightGreenZone = 12;
ChainingOutCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingOutCueOnShotCheckGeneral = true;
break;
case Preset.SDI:
Gap = 4;
@ -3075,15 +3083,19 @@ $HorzAlign = Center
ChainingGeneralMaxGap = 1000;
ChainingGeneralLeftGreenZone = 25;
ChainingGeneralLeftRedZone = 24;
ChainingGeneralShotChangeBehavior = ChainingGeneralShotChangeBehaviorEnum.ExtendCrossingShotChange;
ChainingGeneralShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange;
ChainingInCueOnShotUseZones = false;
ChainingInCueOnShotMaxGap = 1000;
ChainingInCueOnShotLeftGreenZone = 25;
ChainingInCueOnShotLeftRedZone = 24;
ChainingOutCueOnShotUseZones = false;
ChainingOutCueOnShotMaxGap = 1000;
ChainingOutCueOnShotRightRedZone = 24;
ChainingOutCueOnShotRightGreenZone = 25;
ChainingInCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange;
ChainingInCueOnShotCheckGeneral = true;
ChainingOutCueOnShotUseZones = true;
ChainingOutCueOnShotMaxGap = 500;
ChainingOutCueOnShotRightRedZone = 7;
ChainingOutCueOnShotRightGreenZone = 12;
ChainingOutCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange;
ChainingOutCueOnShotCheckGeneral = true;
break;
default:
Gap = 3;
@ -3114,15 +3126,19 @@ $HorzAlign = Center
ChainingGeneralMaxGap = 1000;
ChainingGeneralLeftGreenZone = 25;
ChainingGeneralLeftRedZone = 24;
ChainingGeneralShotChangeBehavior = ChainingGeneralShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingGeneralShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingInCueOnShotUseZones = false;
ChainingInCueOnShotMaxGap = 1000;
ChainingInCueOnShotLeftGreenZone = 25;
ChainingInCueOnShotLeftRedZone = 24;
ChainingInCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingInCueOnShotCheckGeneral = true;
ChainingOutCueOnShotUseZones = false;
ChainingOutCueOnShotMaxGap = 500;
ChainingOutCueOnShotRightRedZone = 11;
ChainingOutCueOnShotRightGreenZone = 12;
ChainingOutCueOnShotShotChangeBehavior = ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
ChainingOutCueOnShotCheckGeneral = true;
break;
}
}
@ -8961,7 +8977,7 @@ $HorzAlign = Center
subNode = profileNode.SelectSingleNode("ChainingGeneralShotChangeBehavior");
if (subNode != null)
{
settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum)Enum.Parse(typeof(BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum), subNode.InnerText);
settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum)Enum.Parse(typeof(BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum), subNode.InnerText);
}
subNode = profileNode.SelectSingleNode("ChainingInCueOnShotUseZones");
@ -8988,6 +9004,18 @@ $HorzAlign = Center
settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftRedZone = Convert.ToInt32(subNode.InnerText, CultureInfo.InvariantCulture);
}
subNode = profileNode.SelectSingleNode("ChainingInCueOnShotShotChangeBehavior");
if (subNode != null)
{
settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum)Enum.Parse(typeof(BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum), subNode.InnerText);
}
subNode = profileNode.SelectSingleNode("ChainingInCueOnShotCheckGeneral");
if (subNode != null)
{
settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotCheckGeneral = Convert.ToBoolean(subNode.InnerText, CultureInfo.InvariantCulture);
}
subNode = profileNode.SelectSingleNode("ChainingOutCueOnShotUseZones");
if (subNode != null)
{
@ -9011,6 +9039,18 @@ $HorzAlign = Center
{
settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightGreenZone = Convert.ToInt32(subNode.InnerText, CultureInfo.InvariantCulture);
}
subNode = profileNode.SelectSingleNode("ChainingOutCueOnShotShotChangeBehavior");
if (subNode != null)
{
settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum)Enum.Parse(typeof(BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum), subNode.InnerText);
}
subNode = profileNode.SelectSingleNode("ChainingOutCueOnShotCheckGeneral");
if (subNode != null)
{
settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotCheckGeneral = Convert.ToBoolean(subNode.InnerText, CultureInfo.InvariantCulture);
}
}
}
@ -12436,10 +12476,14 @@ $HorzAlign = Center
textWriter.WriteElementString("ChainingInCueOnShotMaxGap", settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotMaxGap.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingInCueOnShotLeftGreenZone", settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftGreenZone.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingInCueOnShotLeftRedZone", settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftRedZone.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingInCueOnShotShotChangeBehavior", settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotShotChangeBehavior.ToString());
textWriter.WriteElementString("ChainingInCueOnShotCheckGeneral", settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotCheckGeneral.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingOutCueOnShotUseZones", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotUseZones.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingOutCueOnShotMaxGap", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotMaxGap.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingOutCueOnShotRightRedZone", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightRedZone.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingOutCueOnShotRightGreenZone", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightGreenZone.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("ChainingOutCueOnShotShotChangeBehavior", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotShotChangeBehavior.ToString());
textWriter.WriteElementString("ChainingOutCueOnShotCheckGeneral", settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotCheckGeneral.ToString(CultureInfo.InvariantCulture));
textWriter.WriteEndElement();
textWriter.WriteEndElement();

View File

@ -518,6 +518,8 @@ namespace Nikse.SubtitleEdit.Core.Forms
var isLeftOutCueOnShotChange = IsCueOnShotChange(bestLeftOutCueFrame, false);
var isRightInCueOnShotChange = IsCueOnShotChange(bestRightInCueFrame, true);
var performGeneralChaining = false;
if (isRightInCueOnShotChange)
{
// The right in cue is on a shot change
@ -525,40 +527,121 @@ namespace Nikse.SubtitleEdit.Core.Forms
var fixedLeftOutCueFrame = GetFixedChainableSubtitlesLeftOutCueFrameInCueOnShot(bestLeftOutCueFrame, bestRightInCueFrame);
if (fixedLeftOutCueFrame != null)
{
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
// Check if there are any other shot changes *before* the shot change we want to chain towards
var firstShotChangeInBetween = GetFirstShotChangeFrameInBetween(bestLeftOutCueFrame, bestRightInCueFrame);
if (firstShotChangeInBetween != null && !IsCueOnShotChange(bestRightInCueFrame, true, firstShotChangeInBetween.Value)) {
// There is another shot change in between. Check behaviors
switch (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotShotChangeBehavior)
{
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.DontChain:
// Don't do anything
return false;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange:
// Apply the chaining
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
break;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendUntilShotChange:
// Put the left out cue on the shot change, minus gap
newLeftOutCueFrame = firstShotChangeInBetween.Value - Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
newRightInCueFrame = bestRightInCueFrame;
break;
}
}
else
{
// No shot changes in between, just apply the chaining
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
}
}
else
{
// Chaining wasn't needed
return false;
// If set, we will still check the general rules
if (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotCheckGeneral)
{
performGeneralChaining = true;
}
else
{
// Chaining wasn't needed
return false;
}
}
}
else if (isLeftOutCueOnShotChange)
{
// The left out cue in on a shot change
// The left out cue is on a shot change
// Try to chain the subtitles
var fixedRightInCueFrame = GetFixedChainableSubtitlesRightInCueFrameOutCueOnShot(bestLeftOutCueFrame, bestRightInCueFrame);
if (fixedRightInCueFrame != null)
{
newLeftOutCueFrame = bestLeftOutCueFrame;
newRightInCueFrame = fixedRightInCueFrame.Value;
// Check if there are any other shot changes *after* the shot change we want to chain towards
var lastShotChangeInBetween = GetLastShotChangeFrameInBetween(bestLeftOutCueFrame, bestRightInCueFrame);
if (lastShotChangeInBetween != null && !IsCueOnShotChange(bestLeftOutCueFrame, false, lastShotChangeInBetween.Value))
{
// There is another shot change in between. Check behaviors
switch (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotShotChangeBehavior)
{
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.DontChain:
// Don't do anything
return false;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange:
// Apply the chaining
newLeftOutCueFrame = bestLeftOutCueFrame;
newRightInCueFrame = fixedRightInCueFrame.Value;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
break;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendUntilShotChange:
// Put the right in cue on the shot change, plus gap
newLeftOutCueFrame = bestLeftOutCueFrame;
newRightInCueFrame = lastShotChangeInBetween.Value + Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
break;
}
}
else
{
// No shot changes in between, just apply the chaining
newLeftOutCueFrame = bestLeftOutCueFrame;
newRightInCueFrame = fixedRightInCueFrame.Value;
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
}
}
else
{
// Chaining wasn't needed
return false;
// If set, we will still check the general rules
if (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotCheckGeneral)
{
performGeneralChaining = true;
}
else
{
// Chaining wasn't needed
return false;
}
}
}
else
{
// The cues are not on shot changes
// So, perform general chaining
performGeneralChaining = true;
}
if (performGeneralChaining)
{
// Try to chain the subtitles already, maybe chaining is not needed
var fixedLeftOutCueFrame = GetFixedChainableSubtitlesLeftOutCueFrameGeneral(bestLeftOutCueFrame, bestRightInCueFrame);
if (fixedLeftOutCueFrame != null)
@ -570,18 +653,28 @@ namespace Nikse.SubtitleEdit.Core.Forms
// There are shot changes in between. Check behaviors
switch (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior)
{
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum.DontChain:
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.DontChain:
// Don't do anything
return false;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum.ExtendCrossingShotChange:
// Apply the chaining
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendCrossingShotChange:
// Check if the right in cue was moved forward
if (bestRightInCueFrameInfo.result == FindBestCueResult.SnappedToRightGreenZone)
{
// Yes, then we'll want to use the original position instead: after chaining, the connected subtitles might partially end up in a red zone,
// leading to both being snapped to a shot change before (moving backward). Consequently, only the left out cue needs to be changed.
newLeftOutCueFrame = newRightInCueFrame - Configuration.Settings.BeautifyTimeCodes.Profile.Gap;
}
else
{
// Apply the chaining normally
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
}
// Make sure the newly connected subtitles get fixed
shouldFixConnectedSubtitles = true;
break;
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum.ExtendUntilShotChange:
case BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendUntilShotChange:
// Put the left out cue on the shot change, minus gap
newLeftOutCueFrame = firstShotChangeInBetween.Value - Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
newRightInCueFrame = bestRightInCueFrame;
@ -590,7 +683,7 @@ namespace Nikse.SubtitleEdit.Core.Forms
}
else
{
// Apply the chaining
// No shot changes in between, just apply the chaining
newLeftOutCueFrame = fixedLeftOutCueFrame.Value;
newRightInCueFrame = bestRightInCueFrame;
}
@ -731,7 +824,7 @@ namespace Nikse.SubtitleEdit.Core.Forms
{
var leftOutCueWithGreenZone = leftOutCueFrame + Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightGreenZone;
var isInGreenZone = rightInCueFrame < leftOutCueWithGreenZone && rightInCueFrame > (leftOutCueFrame + Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightRedZone);
var isInRedZone = rightInCueFrame <= (leftOutCueFrame + Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftRedZone) && rightInCueFrame >= leftOutCueFrame;
var isInRedZone = rightInCueFrame <= (leftOutCueFrame + Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightRedZone) && rightInCueFrame >= leftOutCueFrame;
if (isInRedZone)
{
@ -1026,14 +1119,7 @@ namespace Nikse.SubtitleEdit.Core.Forms
var closestShotChangeFrame = GetClosestShotChangeFrame(cueFrame);
if (closestShotChangeFrame != null)
{
if (isInCue)
{
return cueFrame >= closestShotChangeFrame.Value && cueFrame <= closestShotChangeFrame.Value + Configuration.Settings.BeautifyTimeCodes.Profile.InCuesGap;
}
else
{
return cueFrame <= closestShotChangeFrame.Value && cueFrame >= closestShotChangeFrame.Value - Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
}
return IsCueOnShotChange(cueFrame, isInCue, closestShotChangeFrame.Value);
}
else
{
@ -1041,6 +1127,18 @@ namespace Nikse.SubtitleEdit.Core.Forms
}
}
private bool IsCueOnShotChange(int cueFrame, bool isInCue, int shotChangeFrame)
{
if (isInCue)
{
return cueFrame >= shotChangeFrame && cueFrame <= shotChangeFrame + Configuration.Settings.BeautifyTimeCodes.Profile.InCuesGap;
}
else
{
return cueFrame <= shotChangeFrame && cueFrame >= shotChangeFrame - Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
}
}
// Delegates
@ -1063,5 +1161,43 @@ namespace Nikse.SubtitleEdit.Core.Forms
{
return GetFrameDurationMs(frameRate) * Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
}
public static int GetSmallestMaxGapFrames(double? frameRate = null)
{
var frameDurationMs = GetFrameDurationMs(frameRate);
int smallestMaxGapFrames = int.MaxValue;
if (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralUseZones)
{
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftGreenZone);
}
else
{
var maxGap = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralMaxGap / frameDurationMs;
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Convert.ToInt32(Math.Round(maxGap)));
}
if (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotUseZones)
{
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftGreenZone);
}
else
{
var maxGap = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotMaxGap / frameDurationMs;
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Convert.ToInt32(Math.Round(maxGap)));
}
if (Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotUseZones)
{
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightGreenZone);
}
else
{
var maxGap = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotMaxGap / frameDurationMs;
smallestMaxGapFrames = Math.Min(smallestMaxGapFrames, Convert.ToInt32(Math.Round(maxGap)));
}
return smallestMaxGapFrames;
}
}
}

View File

@ -1,11 +1,13 @@
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Core.Forms;
using Nikse.SubtitleEdit.Core.SubtitleFormats;
using Nikse.SubtitleEdit.Forms.ShotChanges;
using Nikse.SubtitleEdit.Logic;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using MessageBox = Nikse.SubtitleEdit.Forms.SeMsgBox.MessageBox;
@ -25,6 +27,14 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
public List<double> ShotChangesInSeconds = new List<double>(); // For storing imported/generated shot changes that will be returned to the main form
public Subtitle FixedSubtitle { get; private set; }
public List<UnfixableParagraphsPair> UnfixableParagraphs { get; private set; }
public struct UnfixableParagraphsPair
{
public Paragraph leftParagraph;
public Paragraph rightParagraph;
public int gapFrames;
}
private bool _abortTimeCodes;
private TimeCodesGenerator _timeCodesGenerator;
@ -287,6 +297,9 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
};
timeCodesBeautifier.Beautify();
// Check for any paragraphs that still have a gap smaller than the smallest max. gap
CheckUnfixableParagraphs();
// Re-enable group boxes, otherwise child controls are also disabled, and we need their original state for the checks below
groupBoxTimeCodes.Enabled = true;
groupBoxShotChanges.Enabled = true;
@ -307,6 +320,36 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
DialogResult = DialogResult.OK;
}
private void CheckUnfixableParagraphs()
{
var minGap = Configuration.Settings.BeautifyTimeCodes.Profile.Gap;
var minGapInCueClosest = Configuration.Settings.BeautifyTimeCodes.Profile.ConnectedSubtitlesInCueClosestLeftGap + Configuration.Settings.BeautifyTimeCodes.Profile.ConnectedSubtitlesInCueClosestRightGap;
var minGapOutCueClosest = Configuration.Settings.BeautifyTimeCodes.Profile.ConnectedSubtitlesOutCueClosestLeftGap + Configuration.Settings.BeautifyTimeCodes.Profile.ConnectedSubtitlesOutCueClosestRightGap;
var smallestMaxGapFrames = TimeCodesBeautifierUtils.GetSmallestMaxGapFrames(_frameRate);
UnfixableParagraphs = new List<UnfixableParagraphsPair>();
for (var p = 0; p < FixedSubtitle.Paragraphs.Count - 2; p++)
{
var paragraph = FixedSubtitle.Paragraphs.ElementAtOrDefault(p);
var nextParagraph = FixedSubtitle.Paragraphs.ElementAtOrDefault(p + 1);
if (paragraph != null && nextParagraph != null)
{
var gapFrames = SubtitleFormat.MillisecondsToFrames(nextParagraph.StartTime.TotalMilliseconds - paragraph.EndTime.TotalMilliseconds, _frameRate);
if (gapFrames < smallestMaxGapFrames && gapFrames != minGap && gapFrames != minGapInCueClosest && gapFrames != minGapOutCueClosest)
{
UnfixableParagraphs.Add(new UnfixableParagraphsPair()
{
leftParagraph = paragraph,
rightParagraph = nextParagraph,
gapFrames = gapFrames
});
}
}
}
}
private void checkBoxAlignTimeCodes_CheckedChanged(object sender, EventArgs e)
{
RefreshControls();

View File

@ -104,6 +104,8 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
this.radioButtonChainingOutCueOnShotMaxGap = new System.Windows.Forms.RadioButton();
this.numericUpDownChainingOutCueOnShotMaxGap = new Nikse.SubtitleEdit.Controls.NikseUpDown();
this.buttonCreateSimple = new System.Windows.Forms.Button();
this.checkBoxChainingInCueOnShotCheckGeneral = new System.Windows.Forms.CheckBox();
this.checkBoxChainingOutCueOnShotCheckGeneral = new System.Windows.Forms.CheckBox();
this.menuStrip.SuspendLayout();
this.groupBoxGeneral.SuspendLayout();
this.groupBoxInCues.SuspendLayout();
@ -1482,6 +1484,7 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
//
// tabPageChainingInCueOnShot
//
this.tabPageChainingInCueOnShot.Controls.Add(this.checkBoxChainingInCueOnShotCheckGeneral);
this.tabPageChainingInCueOnShot.Controls.Add(this.labelChainingInCueOnShotMaxGapSuffix);
this.tabPageChainingInCueOnShot.Controls.Add(this.radioButtonChainingInCueOnShotZones);
this.tabPageChainingInCueOnShot.Controls.Add(this.radioButtonChainingInCueOnShotMaxGap);
@ -1646,6 +1649,7 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
//
// tabPageChainingOutCueOnShot
//
this.tabPageChainingOutCueOnShot.Controls.Add(this.checkBoxChainingOutCueOnShotCheckGeneral);
this.tabPageChainingOutCueOnShot.Controls.Add(this.numericUpDownChainingOutCueOnShotRightGreenZone);
this.tabPageChainingOutCueOnShot.Controls.Add(this.numericUpDownChainingOutCueOnShotRightRedZone);
this.tabPageChainingOutCueOnShot.Controls.Add(this.labelChainingOutCueOnShotMaxGapSuffix);
@ -1816,6 +1820,30 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
this.buttonCreateSimple.UseVisualStyleBackColor = true;
this.buttonCreateSimple.Click += new System.EventHandler(this.buttonCreateSimple_Click);
//
// checkBoxChainingInCueOnShotCheckGeneral
//
this.checkBoxChainingInCueOnShotCheckGeneral.AutoSize = true;
this.checkBoxChainingInCueOnShotCheckGeneral.Checked = true;
this.checkBoxChainingInCueOnShotCheckGeneral.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBoxChainingInCueOnShotCheckGeneral.Location = new System.Drawing.Point(0, 78);
this.checkBoxChainingInCueOnShotCheckGeneral.Name = "checkBoxChainingInCueOnShotCheckGeneral";
this.checkBoxChainingInCueOnShotCheckGeneral.Size = new System.Drawing.Size(251, 19);
this.checkBoxChainingInCueOnShotCheckGeneral.TabIndex = 16;
this.checkBoxChainingInCueOnShotCheckGeneral.Text = "Still enforce General rules when unaffected";
this.checkBoxChainingInCueOnShotCheckGeneral.UseVisualStyleBackColor = true;
//
// checkBoxChainingOutCueOnShotCheckGeneral
//
this.checkBoxChainingOutCueOnShotCheckGeneral.AutoSize = true;
this.checkBoxChainingOutCueOnShotCheckGeneral.Checked = true;
this.checkBoxChainingOutCueOnShotCheckGeneral.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBoxChainingOutCueOnShotCheckGeneral.Location = new System.Drawing.Point(0, 78);
this.checkBoxChainingOutCueOnShotCheckGeneral.Name = "checkBoxChainingOutCueOnShotCheckGeneral";
this.checkBoxChainingOutCueOnShotCheckGeneral.Size = new System.Drawing.Size(251, 19);
this.checkBoxChainingOutCueOnShotCheckGeneral.TabIndex = 26;
this.checkBoxChainingOutCueOnShotCheckGeneral.Text = "Still enforce General rules when unaffected";
this.checkBoxChainingOutCueOnShotCheckGeneral.UseVisualStyleBackColor = true;
//
// BeautifyTimeCodesProfile
//
this.AcceptButton = this.buttonOK;
@ -1950,5 +1978,7 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
private System.Windows.Forms.Label labelConnectedSubtitlesOutCueClosestGaps;
private Controls.CuesPreviewView cuesPreviewViewConnectedSubtitlesOutCueClosest;
private System.Windows.Forms.Button buttonCreateSimple;
private System.Windows.Forms.CheckBox checkBoxChainingInCueOnShotCheckGeneral;
private System.Windows.Forms.CheckBox checkBoxChainingOutCueOnShotCheckGeneral;
}
}

View File

@ -64,10 +64,12 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
radioButtonChainingInCueOnShotMaxGap.Text = language.MaxGap;
labelChainingInCueOnShotMaxGapSuffix.Text = language.Milliseconds;
radioButtonChainingInCueOnShotZones.Text = language.Zones;
checkBoxChainingInCueOnShotCheckGeneral.Text = language.CheckGeneral;
tabPageChainingOutCueOnShot.Text = language.OutCueOnShot;
radioButtonChainingOutCueOnShotMaxGap.Text = language.MaxGap;
labelChainingOutCueOnShotMaxGapSuffix.Text = language.Milliseconds;
radioButtonChainingOutCueOnShotZones.Text = language.Zones;
checkBoxChainingOutCueOnShotCheckGeneral.Text = language.CheckGeneral;
cuesPreviewViewInCues.PreviewText = language.SubtitlePreviewText;
cuesPreviewViewOutCues.PreviewText = language.SubtitlePreviewText;
@ -155,12 +157,14 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
numericUpDownChainingInCueOnShotMaxGap.Value = settings.ChainingInCueOnShotMaxGap;
numericUpDownChainingInCueOnShotLeftRedZone.Value = settings.ChainingInCueOnShotLeftRedZone;
numericUpDownChainingInCueOnShotLeftGreenZone.Value = settings.ChainingInCueOnShotLeftGreenZone;
checkBoxChainingInCueOnShotCheckGeneral.Checked = settings.ChainingInCueOnShotCheckGeneral;
radioButtonChainingOutCueOnShotZones.Checked = settings.ChainingOutCueOnShotUseZones;
radioButtonChainingOutCueOnShotMaxGap.Checked = !settings.ChainingOutCueOnShotUseZones;
numericUpDownChainingOutCueOnShotMaxGap.Value = settings.ChainingOutCueOnShotMaxGap;
numericUpDownChainingOutCueOnShotRightRedZone.Value = settings.ChainingOutCueOnShotRightRedZone;
numericUpDownChainingOutCueOnShotRightGreenZone.Value = settings.ChainingOutCueOnShotRightGreenZone;
checkBoxChainingOutCueOnShotCheckGeneral.Checked = settings.ChainingOutCueOnShotCheckGeneral;
RefreshControls();
}
@ -233,6 +237,9 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
private void buttonOK_Click(object sender, EventArgs e)
{
// Remember value for check later on
var previousGeneralShotChangeBehavior = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior;
// Save settings
Configuration.Settings.BeautifyTimeCodes.Profile.Gap = Convert.ToInt32(numericUpDownGap.Value);
@ -262,17 +269,26 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralMaxGap = Convert.ToInt32(numericUpDownChainingGeneralMaxGap.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftGreenZone = Convert.ToInt32(numericUpDownChainingGeneralLeftGreenZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftRedZone = Convert.ToInt32(numericUpDownChainingGeneralLeftRedZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum)comboBoxChainingGeneralShotChangeBehavior.SelectedIndex;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = (BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum)comboBoxChainingGeneralShotChangeBehavior.SelectedIndex;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotUseZones = radioButtonChainingInCueOnShotZones.Checked;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotMaxGap = Convert.ToInt32(numericUpDownChainingInCueOnShotMaxGap.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftGreenZone = Convert.ToInt32(numericUpDownChainingInCueOnShotLeftGreenZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotLeftRedZone = Convert.ToInt32(numericUpDownChainingInCueOnShotLeftRedZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotCheckGeneral = checkBoxChainingInCueOnShotCheckGeneral.Checked;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotUseZones = radioButtonChainingOutCueOnShotZones.Checked;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotMaxGap = Convert.ToInt32(numericUpDownChainingOutCueOnShotMaxGap.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightRedZone = Convert.ToInt32(numericUpDownChainingOutCueOnShotRightRedZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotRightGreenZone = Convert.ToInt32(numericUpDownChainingOutCueOnShotRightGreenZone.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotCheckGeneral = checkBoxChainingOutCueOnShotCheckGeneral.Checked;
// Update hidden shot change behavior settings if value for general bahavior has changed
if (previousGeneralShotChangeBehavior != Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior)
{
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotShotChangeBehavior = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingOutCueOnShotShotChangeBehavior = Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior;
}
DialogResult = DialogResult.OK;
}

View File

@ -179,7 +179,7 @@ namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralMaxGap = Convert.ToInt32(numericUpDownChainingGap.Value);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftGreenZone = GetChainingZoneFrames(Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralMaxGap);
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralLeftRedZone = GetChainingZoneFrames(Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralMaxGap) - 1;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingGeneralShotChangeBehaviorEnum.ExtendUntilShotChange;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingGeneralShotChangeBehavior = BeautifyTimeCodesSettings.BeautifyTimeCodesProfile.ChainingShotChangeBehaviorEnum.ExtendUntilShotChange;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotUseZones = false;
Configuration.Settings.BeautifyTimeCodes.Profile.ChainingInCueOnShotMaxGap = Convert.ToInt32(numericUpDownChainingGap.Value);

View File

@ -0,0 +1,120 @@
namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
{
partial class BeautifyTimeCodesUnfixableParagraphs
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BeautifyTimeCodesUnfixableParagraphs));
this.buttonClose = new System.Windows.Forms.Button();
this.labelInstructions = new System.Windows.Forms.Label();
this.listView = new System.Windows.Forms.ListView();
this.columnHeaderParagraphs = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeaderGap = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuspendLayout();
//
// buttonClose
//
this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.OK;
this.buttonClose.Location = new System.Drawing.Point(397, 356);
this.buttonClose.Name = "buttonClose";
this.buttonClose.Size = new System.Drawing.Size(75, 23);
this.buttonClose.TabIndex = 10;
this.buttonClose.Text = "Close";
this.buttonClose.UseVisualStyleBackColor = true;
this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click);
//
// labelInstructions
//
this.labelInstructions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.labelInstructions.AutoEllipsis = true;
this.labelInstructions.Location = new System.Drawing.Point(12, 9);
this.labelInstructions.Name = "labelInstructions";
this.labelInstructions.Size = new System.Drawing.Size(460, 80);
this.labelInstructions.TabIndex = 1;
this.labelInstructions.Text = resources.GetString("labelInstructions.Text");
//
// listView
//
this.listView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeaderParagraphs,
this.columnHeaderGap});
this.listView.FullRowSelect = true;
this.listView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listView.HideSelection = false;
this.listView.Location = new System.Drawing.Point(13, 92);
this.listView.MultiSelect = false;
this.listView.Name = "listView";
this.listView.Size = new System.Drawing.Size(458, 258);
this.listView.TabIndex = 2;
this.listView.UseCompatibleStateImageBehavior = false;
this.listView.View = System.Windows.Forms.View.Details;
this.listView.SelectedIndexChanged += new System.EventHandler(this.listView_SelectedIndexChanged);
this.listView.Click += new System.EventHandler(this.listView_Click);
//
// columnHeaderParagraphs
//
this.columnHeaderParagraphs.Width = 150;
//
// columnHeaderGap
//
this.columnHeaderGap.Width = 150;
//
// BeautifyTimeCodesUnfixableParagraphs
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(484, 391);
this.Controls.Add(this.listView);
this.Controls.Add(this.labelInstructions);
this.Controls.Add(this.buttonClose);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.MaximizeBox = false;
this.MinimumSize = new System.Drawing.Size(460, 250);
this.Name = "BeautifyTimeCodesUnfixableParagraphs";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Review not fully chained subtitles";
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.BeautifyTimeCodesUnfixableParagraphs_KeyDown);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button buttonClose;
private System.Windows.Forms.Label labelInstructions;
private System.Windows.Forms.ListView listView;
private System.Windows.Forms.ColumnHeader columnHeaderParagraphs;
private System.Windows.Forms.ColumnHeader columnHeaderGap;
}
}

View File

@ -0,0 +1,78 @@
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Logic;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using static Nikse.SubtitleEdit.Forms.BeautifyTimeCodes.BeautifyTimeCodes;
namespace Nikse.SubtitleEdit.Forms.BeautifyTimeCodes
{
public partial class BeautifyTimeCodesUnfixableParagraphs : Form
{
private readonly List<UnfixableParagraphsPair> _paragraphs;
private readonly Action<Paragraph> _selectParagraphAction;
public BeautifyTimeCodesUnfixableParagraphs(List<UnfixableParagraphsPair> paragraphs, Action<Paragraph> selectParagraphAction)
{
_paragraphs = paragraphs;
_selectParagraphAction = selectParagraphAction;
UiUtil.PreInitialize(this);
InitializeComponent();
UiUtil.FixFonts(this);
var language = LanguageSettings.Current.BeautifyTimeCodes;
Text = language.UnfixableParagraphsTitle;
labelInstructions.Text = language.UnfixableParagraphsInstructions;
columnHeaderParagraphs.Text = language.UnfixableParagraphsColumnParagraphs;
columnHeaderGap.Text = language.UnfixableParagraphsColumnGap;
buttonClose.Text = LanguageSettings.Current.General.Close;
UiUtil.FixLargeFonts(this, buttonClose);
PopulateListView();
}
private void PopulateListView()
{
listView.BeginUpdate();
foreach (var pair in _paragraphs)
{
listView.Items.Add(new ListViewItem(new[] {
String.Format(LanguageSettings.Current.BeautifyTimeCodes.UnfixableParagraphsColumnParagraphsFormat, pair.leftParagraph.Number, pair.rightParagraph.Number),
pair.gapFrames.ToString()
}));
}
listView.EndUpdate();
}
private void BeautifyTimeCodesUnfixableParagraphs_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}
private void buttonClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView.SelectedIndices.Count > 0)
{
var index = listView.SelectedIndices[0];
var pair = _paragraphs[index];
_selectParagraphAction.Invoke(pair.rightParagraph);
}
}
private void listView_Click(object sender, EventArgs e)
{
listView_SelectedIndexChanged(sender, e);
}
}
}

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="labelInstructions.Text" xml:space="preserve">
<value>Some subtitles were not fully chained in accordance with your profile, most likely due to too tightly clustered shot changes (possibly false positives).
You might want to review these cases manually to ensure your cues are snapped to the correct (real) shot changes.
</value>
</data>
</root>

View File

@ -119,6 +119,7 @@ namespace Nikse.SubtitleEdit.Forms
private FindReplaceDialogHelper _findHelper;
private FindDialog _findDialog;
private ReplaceDialog _replaceDialog;
private Form _dialog;
private bool _sourceViewChange;
private int _changeSubtitleHash = -1;
private int _changeOriginalSubtitleHash = -1;
@ -36213,6 +36214,8 @@ namespace Nikse.SubtitleEdit.Forms
return;
}
var unfixableParagraphs = new List<BeautifyTimeCodes.BeautifyTimeCodes.UnfixableParagraphsPair>();
if (onlySelectedLines)
{
var selectedIndices = SubtitleListview1.GetSelectedIndices();
@ -36259,6 +36262,8 @@ namespace Nikse.SubtitleEdit.Forms
RestoreSubtitleListviewIndices();
ShowStatus(_language.BeautifiedTimeCodesSelectedLines);
unfixableParagraphs = form.UnfixableParagraphs;
}
}
}
@ -36291,9 +36296,24 @@ namespace Nikse.SubtitleEdit.Forms
RestoreSubtitleListviewIndices();
ShowStatus(_language.BeautifiedTimeCodes);
unfixableParagraphs = form.UnfixableParagraphs;
}
}
}
if (unfixableParagraphs.Count > 0)
{
BeginInvoke(new Action(() => {
_dialog?.Dispose();
_dialog = new BeautifyTimeCodes.BeautifyTimeCodesUnfixableParagraphs(unfixableParagraphs, (paragraph) =>
{
SubtitleListview1.SelectIndexAndEnsureVisible(paragraph);
GotoSubPositionAndPause();
});
_dialog.Show(this);
}));
}
}
private void ToolStripSplitButtonPlayRateClick(object sender, EventArgs e)

View File

@ -147,6 +147,7 @@ namespace Nikse.SubtitleEdit.Logic
Cancel = "C&ancel",
Yes = "Yes",
No = "No",
Close = "Close",
Apply = "Apply",
ApplyTo = "Apply to",
None = "None",
@ -579,6 +580,13 @@ namespace Nikse.SubtitleEdit.Logic
BatchAlignTimeCodes = "Align time codes to frame time codes",
BatchUseExactTimeCodes = "Use exact time codes (if available)",
BatchSnapToShotChanges = "Snap cues to shot changes (if available)",
UnfixableParagraphsTitle = "Review not fully chained subtitles",
UnfixableParagraphsInstructions = "Some subtitles were not fully chained in accordance with your profile, most likely due to too tightly clustered shot changes (possibly false positives)." +
Environment.NewLine + Environment.NewLine +
"You might want to review these cases manually to ensure your cues are snapped to the correct (real) shot changes.",
UnfixableParagraphsColumnParagraphs = "Lines",
UnfixableParagraphsColumnParagraphsFormat = "#{0} #{1}",
UnfixableParagraphsColumnGap = "Gap (frames)"
};
BeautifyTimeCodesProfile = new LanguageStructure.BeautifyTimeCodesProfile
@ -604,6 +612,7 @@ namespace Nikse.SubtitleEdit.Logic
Chaining = "Chaining",
InCueOnShot = "In cue on shot change",
OutCueOnShot = "Out cue on shot change",
CheckGeneral = "Still enforce General rules when unaffected",
MaxGap = "Max. gap:",
ShotChangeBehavior = "If there is a shot change in between:",
DontChain = "Don't chain",

View File

@ -14,6 +14,7 @@
public string Cancel { get; set; }
public string Yes { get; set; }
public string No { get; set; }
public string Close { get; set; }
public string Apply { get; set; }
public string ApplyTo { get; set; }
public string None { get; set; }
@ -422,6 +423,11 @@
public string BatchAlignTimeCodes { get; set; }
public string BatchUseExactTimeCodes { get; set; }
public string BatchSnapToShotChanges { get; set; }
public string UnfixableParagraphsTitle { get; set; }
public string UnfixableParagraphsInstructions { get; set; }
public string UnfixableParagraphsColumnParagraphs { get; set; }
public string UnfixableParagraphsColumnParagraphsFormat { get; set; }
public string UnfixableParagraphsColumnGap { get; set; }
}
public class BeautifyTimeCodesProfile
@ -447,6 +453,7 @@
public string Chaining { get; set; }
public string InCueOnShot { get; set; }
public string OutCueOnShot { get; set; }
public string CheckGeneral { get; set; }
public string MaxGap { get; set; }
public string ShotChangeBehavior { get; set; }
public string DontChain { get; set; }

View File

@ -322,6 +322,12 @@
<Compile Include="Forms\BeautifyTimeCodes\BeautifyTimeCodesProfileSimple.Designer.cs">
<DependentUpon>BeautifyTimeCodesProfileSimple.cs</DependentUpon>
</Compile>
<Compile Include="Forms\BeautifyTimeCodes\BeautifyTimeCodesUnfixableParagraphs.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\BeautifyTimeCodes\BeautifyTimeCodesUnfixableParagraphs.Designer.cs">
<DependentUpon>BeautifyTimeCodesUnfixableParagraphs.cs</DependentUpon>
</Compile>
<Compile Include="Forms\BinaryEdit\BinEdit.cs">
<SubType>Form</SubType>
</Compile>
@ -1738,6 +1744,9 @@
<EmbeddedResource Include="Forms\BeautifyTimeCodes\BeautifyTimeCodesProfileSimple.resx">
<DependentUpon>BeautifyTimeCodesProfileSimple.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\BeautifyTimeCodes\BeautifyTimeCodesUnfixableParagraphs.resx">
<DependentUpon>BeautifyTimeCodesUnfixableParagraphs.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\BinaryEdit\BinEdit.resx">
<DependentUpon>BinEdit.cs</DependentUpon>
</EmbeddedResource>