Add frame-based min-gap setting (#11084)#11099
Merged
Merged
Conversation
Wraps the min-gap between lines in an MsOrFramesValue that stores both a millisecond and a frame value. When UseFrameMode is on, the frame value is converted to ms via the current frame rate; otherwise the ms value is used directly. The Settings UI swaps label and control based on the mode, and shows the ms equivalent next to the frame input. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a frame-based alternative for the “minimum gap between lines” setting, so gap enforcement can respect Use frame mode while still preserving a millisecond value for non-frame workflows.
Changes:
- Introduces
MsOrFramesValueand replacesMinimumMillisecondsBetweenLineswithMinimumBetweenLinesin general settings. - Updates many min-gap consumers to use
MinimumBetweenLines.GetMilliseconds()so frame mode affects enforcement. - Extends Settings UI/localization to show a frames input + ms equivalent hint when frame mode is enabled.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ui/Logic/UiUtil.cs | Adds generic WithBindIsVisible helpers used by the Settings UI. |
| src/ui/Logic/SubtitleGridCopyPasteHelper.cs | Uses effective min-gap ms when pasting to compute insert timing. |
| src/ui/Logic/ISplitManager.cs | Uses effective min-gap ms when splitting subtitles. |
| src/ui/Logic/InsertService.cs | Uses effective min-gap ms when inserting before/after. |
| src/ui/Logic/Config/SeGeneral.cs | Replaces min-gap ms setting with MsOrFramesValue wrapper and default. |
| src/ui/Logic/Config/MsOrFramesValue.cs | New wrapper storing ms+frames and computing effective ms in frame mode. |
| src/ui/Logic/Config/Language/Options/LanguageSettings.cs | Adds localized label for “Min gap (frames)”. |
| src/ui/Features/Video/CutVideo/CutVideoViewModel.cs | Uses effective min-gap ms for cut navigation constraints. |
| src/ui/Features/Tools/FixCommonErrors/FixCommonErrorsViewModel.cs | Pushes effective min-gap ms into libse settings for tools. |
| src/ui/Features/Tools/ApplyMinGap/ApplyMinGapViewModel.cs | Loads min-gap value in frames vs ms depending on frame mode. |
| src/ui/Features/Tools/ApplyDurationLimits/ApplyDurationLimitsViewModel.cs | Uses effective min-gap ms when capping end times. |
| src/ui/Features/Shared/BinaryEdit/BinaryEditViewModel.cs | Uses effective min-gap ms when adjusting binary subtitle timings. |
| src/ui/Features/Options/Settings/SettingsViewModel.cs | Adds frame-mode min-gap fields, label swap, and ms-equivalent hint. |
| src/ui/Features/Options/Settings/SettingsPage.cs | Updates Settings UI row to swap ms/frames inputs and show hint in frame mode. |
| src/ui/Features/Options/Settings/SettingsItem.cs | Adds optional label text binding support for dynamic labels. |
| src/ui/Features/Options/Settings/ProfileDisplay.cs | Maps profile min-gap to the ms slot of the new wrapper. |
| src/ui/Features/Main/SubtitleLineViewModel.cs | Uses effective min-gap ms for gap warnings/errors. |
| src/ui/Features/Main/MainViewModel.cs | Pushes effective min-gap ms into libse and updates various enforcement sites. |
| src/ui/Features/Main/MainHelpers/PasteFromClipboardHelper.cs | Uses effective min-gap ms when generating timings from plain text paste. |
| src/ui/Features/Main/Layout/InitWaveform.cs | Uses effective min-gap ms to configure waveform min-gap display. |
| src/ui/Features/Files/ImportPlainText/ScriptSyncService.cs | Uses effective min-gap ms for script sync constraints. |
| src/ui/Features/Files/ImportPlainText/ImportPlainTextViewModel.cs | Uses effective min-gap ms for import defaults. |
| src/ui/Controls/AudioVisualizerControl/AudioVisualizer.cs | Uses effective min-gap ms when generating timecodes. |
Comment on lines
5128
to
5133
| Se.Settings.General.SubtitleLineMaximumLength = p.SubtitleLineMaximumLength; | ||
| Se.Settings.General.SubtitleMaximumCharactersPerSeconds = (double)p.SubtitleMaximumCharactersPerSeconds; | ||
| Se.Settings.General.SubtitleOptimalCharactersPerSeconds = (double)p.SubtitleOptimalCharactersPerSeconds; | ||
| Se.Settings.General.SubtitleMaximumWordsPerMinute = (double)p.SubtitleMaximumWordsPerMinute; | ||
| Se.Settings.General.MinimumMillisecondsBetweenLines = p.MinimumMillisecondsBetweenLines; | ||
| Se.Settings.General.MinimumBetweenLines.Milliseconds = p.MinimumMillisecondsBetweenLines; | ||
| Se.Settings.General.MaxNumberOfLines = p.MaxNumberOfLines; |
Comment on lines
+58
to
+70
| public string MinGapFramesAsMs | ||
| { | ||
| get | ||
| { | ||
| if (!MinGapFrames.HasValue) | ||
| { | ||
| return string.Empty; | ||
| } | ||
|
|
||
| var fps = Configuration.Settings.General.CurrentFrameRate; | ||
| var ms = SubtitleFormat.FramesToMilliseconds(MinGapFrames.Value, fps); | ||
| return $"= {ms} ms (at {fps.ToString("0.###", CultureInfo.InvariantCulture)} fps)"; | ||
| } |
Comment on lines
+1197
to
+1214
| public static T WithBindIsVisible<T>(this T control, string isVisiblePropertyPath) where T : Control | ||
| { | ||
| control.Bind(Visual.IsVisibleProperty, new Binding | ||
| { | ||
| Path = isVisiblePropertyPath, | ||
| Mode = BindingMode.TwoWay, | ||
| }); | ||
|
|
||
| return control; | ||
| } | ||
|
|
||
| public static T WithBindIsVisible<T>(this T control, object source, string isVisiblePropertyPath) where T : Control | ||
| { | ||
| control.Bind(Visual.IsVisibleProperty, new Binding(isVisiblePropertyPath) | ||
| { | ||
| Source = source, | ||
| Mode = BindingMode.TwoWay, | ||
| }); |
Comment on lines
+35
to
+41
| public SettingsItem(string label, object labelBindingSource, string labelBindingPath, Func<Control> controlFactory) | ||
| { | ||
| _label = label; | ||
| _controlFactory = controlFactory; | ||
| _labelBindingSource = labelBindingSource; | ||
| _labelBindingPath = labelBindingPath; | ||
| } |
- Profile selection now updates both Milliseconds and Frames so frame-mode users see profile-driven min-gap changes too. - OneWay binding for the new generic WithBindIsVisible helpers (IsVisible is sink-only — TwoWay caused write-back errors on computed properties like IsMsMode). - Include both unit variants of the min-gap label in the filter string so search matches whether the user sees "ms" or "frames". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MsOrFramesValuewrapper onSeGeneral.UseFrameModeis on, the Settings UI shows a frames input (with the ms equivalent rendered next to it at lower opacity); when off, the existing ms input is shown. The row label swaps to match.MinimumMillisecondsBetweenLines(~30 sites acrossMainViewModel,BinaryEdit,AudioVisualizer,InsertService, etc.) now go throughMinimumBetweenLines.GetMilliseconds()so frame mode actually takes effect, and the two libse-sync sites push the effective ms through too.Closes #11084.
Test plan
MillisecondsandFrames.🤖 Generated with Claude Code