Skip to content

Fix/settings switch fade - #3

Merged
pdjdev merged 206 commits into
build/osxfrom
fix/settings-switch-fade
Oct 10, 2026
Merged

pdjdev merged 206 commits into
build/osxfrom
fix/settings-switch-fade

Conversation

@pdjdev

@pdjdev pdjdev commented Oct 10, 2026

Copy link
Copy Markdown
Owner

No description provided.

Triathlon-rally and others added 30 commits October 6, 2026 14:57
The copied Ebu.cs reader would drift from production and the project is
not in SubtitleEdit.sln, so CI never ran it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ebu-stl-frame-rate-race

Fix EBU STL import frame-rate race
…titleEdit#15741)

Eight new shortcuts, one per existing "Video, custom milliseconds ... back/forward"
slot. They use the same milliseconds as their twin but pause playback first (like
the Pause shortcut, resetting any play selection), so a jog/shuttle step leaves the
video paused on the new position. No default keys.

The Shortcuts dialog picker blocks for the custom video moves are now one table, so
editing a slot retitles both the plain and the pause variant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dit#15742)

Add folder / dropping a folder now prompts when the scan finds video files
(mkv, mp4, ts...): add their subtitle tracks, subtitle files only, or cancel,
with "Do not ask again". Batch convert settings gets a matching
Ask / Add their subtitle tracks / Skip option, and the settings dialog is
regrouped into Output / Adding files / OCR / Other sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PlayheadFrameStepTests invokes it by reflection, which does not fill optional
parameters; the paused seek now lives in SeekVideoPositionSeconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BatchConvertFileLoader parses "Add files"/"Add folder" with 4 workers and
reports results in file order, one UI update per ~100 ms instead of two posts
per file. Text/binary format detection stays serialized behind a lock - the
shared SubtitleFormat instances keep per-instance state (a parallel test fails
5/5 without it). Containers (MKV/MP4/TS) probe fully in parallel.

Benchmarks: BatchConvertAddFiles*Benchmarks in tests/benchmarks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leedit-issue-15741-7d4eb7

Add "custom milliseconds back/forward and pause" video shortcuts (SubtitleEdit#15741)
…convert-mkv-import-3a0b59

Batch convert: ask before adding video files from a folder (SubtitleEdit#15742)
…convert-faster-add-files

Batch convert: parse added files with a few workers, batch UI updates
CountLines uses the same line break rules as SplitToLines ("\r\r\n" is
two breaks, SubtitleEdit#8854) but only counts, so callers that just need the number
of lines no longer allocate a list plus a substring per line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
New Settings > Waveform checkbox "Remember zoom (horizontal and vertical)",
off by default. When on, horizontal and vertical zoom are saved on close,
restored when the waveform is created, and no longer reset to 100% when an
empty waveform is generated. "Reset waveform zoom & speed" still resets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
org.freedesktop.Platform 24.08 (and its GL.default extensions) is end of
life. Bump the manifests, nuget-sources generator and CI workflows to
26.08, and pin the shared-framework packs to 10.0.12 - the runtime the
dotnet10//26.08 extension ships - so the offline restore matches.

Fixes SubtitleEdit#15754

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dit#15753)

In SMPTE timing the subtitle's times are on the non-drop-frame time code
clock (the video is stretched by 1.001), but the frame helpers still divided
by 24000/1001, so frame numbers drifted 87 frames per hour at 23.976:
frame-number time code mode, frame-count formats (MicroDVD, ...), custom
text "frames" tokens. They now use the whole-number rate (24/30/60) in SMPTE
timing for 23.976/29.97/59.94.

Toggling SMPTE timing on a frame-count format keeps every line on the same
frame, so reopening a recent file in SMPTE timing doesn't shift it by 0.1 %.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MoveWordUpDown treated every "{\...}" block (except \i1) as an opener that never
closes. So the colour was copied onto every moved word, the block in front of the
word stayed behind, and moving a word back and forth piled the tags up. The reset
"{\c&H(style)&}" that Set colour adds was copied as one more colour too.

ASSA text now goes through its own path, which tracks the tags in effect:
- Lines of one subtitle: overrides carry across the line break, so only the
  break moves (no tag added to the second line).
- Between subtitles: the word gets only the tags in effect, the colour is closed
  before the next subtitle's own text, and moving it back merges. Tags for the
  whole subtitle (\an, \pos, \move, \fad, \clip) are no longer copied into the
  other subtitle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alues-persistence-443168

Option to remember waveform zoom across restarts (SubtitleEdit#15748)
…itleEdit#15753)

Final Cut Pro XML (and its two text/test variants) count frames with their
own TotalSeconds * frameRate math, so they kept 23.976 in SMPTE timing. They
now use the whole-number rate there via SubtitleFormat.ToTimeCodeFrameRate,
and StoresFrameNumbers lets the SMPTE toggle keep their lines on the same
frame like MicroDVD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ove-word-tags-15756

Fix ASSA override tags piling up when moving words (SubtitleEdit#15756)
…leedit-issue-15753-6d906d

SMPTE timing: frame numbers follow the NDF time code clock (SubtitleEdit#15753)
Discussion SubtitleEdit#15755 asks for a live TTS player: watch a foreign-language
course while the translated subtitles are spoken, instead of reading them.
Speak from current line ignores time codes and pauses the video, so it
cannot do this.

Video > Play with speech... plays the video and speaks each line when the
video reaches its start. Clips are generated three lines ahead, one at a
time. A clip longer than its line is sped up (max 1.5x); if it still runs
into the next line the video waits for it (option). The video's volume is
lowered while speaking (option). Pausing the video holds the speech,
seeking restarts from the new position, and the waveform toolbar speed
applies to both. Escape, Stop speaking or the command again stops it.

Reuses the Speak from current line prompt (fast engines only) with the
two playback options added, and its clip generation and mpv helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Edit#15753)

FCP X stores rational media time (a 23.976 frame is 1001/24000 s), but in
SMPTE timing the subtitle's times are on the time code clock. All FCP X
formats (1.3-1.14, X Xml, Chapter Marker, Captions, Gap, Name, 1.4 Text) now
write a 1.001-stretched copy and divide by 1.001 after loading - only in
SMPTE timing at 23.976/29.97/59.94. StoresFrameNumbers is set on them so the
SMPTE toggle keeps their lines on the same frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mpte-15753

SMPTE timing: Final Cut Pro X formats write real media time (SubtitleEdit#15753)
SubtitleEdit#15749)

With the original's non-matching lines shown, a matched row only borrows
its original line's text under the translation's time codes. Close
translation promoted the rows in place, so the original's text got the
translation's timing and the promoted display-only rows overlapped it - a
line split in two in the original showed both halves stacked.

Close translation now makes the original itself (edits folded in) the
working subtitle. Folding rows back into the original (capture and save)
keeps each matched line's own time codes and style instead of the row's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leedit-issue-15754-314676

Flatpak: move runtime from EOL freedesktop 24.08 to 26.08
…ges (SubtitleEdit#15749)

Close translation only prompted when the translation had unsaved
changes; otherwise it silently replaced the subtitle being edited with
the original. It sits next to Close original in the File menu, so a
slip went unnoticed. It now asks Yes/No first (the save prompt still
covers the unsaved case).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ith-speech-15755

Add "Play with speech": speak lines in sync while the video plays
niksedk and others added 27 commits October 10, 2026 06:06
The zip path already passes leaveOpen: true because callers hash the
archive afterwards for the .installed.sha256 sidecar. The .tar.gz path
disposed it, so the hash step hit ObjectDisposedException (swallowed)
and no sidecar was written for llama.cpp / IndexTTS 2.5 on macOS/Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the first word of line 2 ended on its own closing tag (<i>One</i>),
that tag stayed in the open-tag list, and a later </i> in the rest of
the line made it get reopened: "<i>One</i> two <i>three</i>" left
"<i>two <i>three</i>" behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MessageBox.Show takes (owner, title, message). Blank video's two
background-image errors and the ASSA/SSA attachments error passed the
explanation as the title and "Error" as the body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nts-footer-load

Keep SSA [Fonts]/[Graphics] in the footer on load
…e-settings-backup-pruned

Restore settings: don't lose the picked backup to the safety-backup prune
…unpack-leave-open

Leave the archive stream open when unpacking .tar.gz
- Right-click on the canvas opens a menu for what is under the pointer: point
  (delete point), shape (duplicate, move to layer, flip, eraser, hide, delete)
  or empty canvas (close/cancel drawing, select all, zoom, grid, preview, clear)
- Shapes tree has a context menu too (layer: hide/show, change layer, delete)
- Select tool picks shapes on the canvas and drags them; middle mouse pans
- Tool strip on the left with the active tool highlighted, grid/preview
  toggles show their state, file actions moved to the right
- Canvas: shapes filled with their layer color, handles only on the selected
  shape, selection box, checkered frame on a dark workspace
- Tree shows icons, layer color swatches and hidden state; selection is kept
  across tree rebuilds and follows canvas picks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…exit, resampler close

- ASSA/SSA attachments: a graphic Skia cannot decode crashed the preview
  (SKBitmap.Decode returns null); show an empty preview instead.
- Batch convert presets now store the six split/break settings, which
  the dialog writes straight into the shared Tools settings.
- Embedded subtitles edit (MKV + MP4): treat a non-zero ffmpeg exit code
  as failure instead of only checking the output file exists.
- ASSA resolution resampler: save the "ask when video opens" checkbox on
  window Closing so the title-bar X honours it too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ord-up-reopened-tag

Move word up: don't reopen the tag the moved word closed
…ebox-title-message-swap

Fix swapped title and message in four error boxes
…t-10-10-extras

Bug hunt 10-10 follow-ups: attachments decode, batch presets, ffmpeg exit, resampler close
- Import SVG button, canvas menu item and drag-and-drop of .svg files
- SvgImporter (SkiaSharp, no new dependency): path/rect/circle/ellipse/
  line/polygon/polyline, <g>/<use>/nested <svg>, transforms baked in,
  arcs/quads/conics converted to cubic beziers, strokes turned into filled
  outlines, fill/stroke color + opacity from attributes, style and simple
  .class rules, gradients use their first stop; each color change starts a
  new layer above the existing drawing
- Holes are wound opposite to their outline, so even-odd and non-zero
  filling render the same
- An SVG with the canvas aspect ratio fills the frame, others are fitted to
  half the frame and centered
- Canvas fills each layer as one geometry (non-zero, eraser shapes cut out)
  so holes show like libass renders them; multi-selections get one box
- Translucent layer colors get the alpha in their style name - a 60% white
  and an opaque white shared a style name and one replaced the other

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CapMaker Plus: merge same-start records backwards; a run of three lost
  its third line and got a zero duration.
- Adjust durations Recalculate: leave the minimum gap before the next
  line and keep a positive duration (ClampEndTime, like Fixed/Percent).
- Second subtitle + D-Cinema Interop/SMPTE color pickers: Initialize(color)
  instead of setting SelectedColor, which left hex/sliders at white.
- D-Cinema SMPTE profile export read the start time's frames as ms; parse
  as HH:MM:SS:FF and read the stored ms culture-invariantly.
- Import plain text: fixed-duration checkbox/ms now refresh the preview
  (and what OK imports).
- ffmpeg media info: also match ffmpeg 4.x "displaymatrix: rotation of".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-10-10-round2

Bug hunt 10-10 round 2: six fixes
- Snapshot of the shapes before every change (close shape, delete, layer
  changes, duplicate, flip, eraser, hide, delete layer/point, clear all,
  load, SVG import, point/shape drags, nudges, point X/Y boxes, layer color)
- While drawing, undo takes back the last click (a bezier click = 3 points)
- Held arrow keys and spinning a number box are one step; a drag is one step
- Selection is restored with the state; 100 steps kept
- Ctrl/Cmd+Z, Ctrl+Y and Ctrl/Cmd+Shift+Z; toolbar buttons and canvas menu

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Select tool shows 8 scale handles and a rotate handle around the selected
  shape or multi-selection; the dragged edge follows the pointer and the
  opposite edge stays put, Shift keeps the aspect ratio (corners) or snaps
  rotation to 15 degrees; size/angle readout while dragging
- Each handle drag is one undo step (applied from the original points, so no
  drift); hover cursors for handles and movable shapes
- Dragging a shape of a multi-selection moves the whole selection; a click
  without drag selects just that shape
- Shape menu: Rotate 90 degrees clockwise / counter-clockwise

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Formats:
- MS Office Workbook: write the Marked cell so rows match the 10-column
  header; alignment (and the actor) were read from the wrong cells.
- D-Cinema Interop: mixed italic/non-italic no longer drops font/bold
  tags; read the Font "Id" attribute (was looking for SMPTE's "ID").
- Projection Subtitle List: an escaped backslash no longer eats the next
  word; "}" closes italics and multi-line italics survive.
- Final Cut Pro text XML: bold-only text is written as bold.
- IMSC 1.1 / TTML 1.0: the frame rate multiplier scales ttp:frameRate
  (60 * 1000/1001 = 59.94) instead of being used as the rate.

Tools:
- Apply duration limits honours unticked Apply checkboxes.
- Batch convert statistics: average gap = total / gap count.
- Modify selection duration rules default to 2000 ms (was 2 ms).

Image export: per-line boxes are offset by the crop's left edge (were
outlineWidth too far left) and measure RTL lines like the renderer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-10-10-round3

Bug hunt 10-10 round 3: eleven fixes
- Point menu: Convert segment to curve (control points at 1/3 and 2/3, so it
  looks the same until one is dragged) / Convert segment to line; on a
  control point it acts on that point's curve
- Shape menu: Convert all lines to curves / Convert all curves to lines
- All undoable; a removed control point hands the selection to its end point
- Selected point X/Y boxes on their own rows (were too narrow for 4 digits)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tleEdit#15869)

Typing a rate that matches no list item makes the editable combo box's
selection null, which the double SelectedFrom/ToFrameRate binding showed
as "Could not convert '(null)' to System.Double". The selection binding
now ignores null so the rate keeps its value until the typed text is
committed, and the commit re-selects the applied rate so re-entering the
current value no longer leaves the box unselected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Background button (toolbar) and canvas menu: video frame at the current
  position, video frame at a typed time code, image file (png/jpg/bmp/webp),
  no background; dropping an image on the window sets it too
- Shown with or without the libass preview (it used to appear only with F9);
  the preview still loads the video frame unless a background was picked
- Images keep their aspect ratio, centered, unless "Stretch image to canvas"
- Opacity slider; opacity and stretch remembered in Settings (Assa)
- A slower ffmpeg grab can't replace a background picked after it started
- Background is display only - never part of the result

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…15869-change-frame-rate-null

Change frame rate: no null-to-double error while typing a rate (SubtitleEdit#15869)
- Always dark editor palette, edge-to-edge panels (options bar, tool strip,
  canvas, shapes panel, status bar, button bar) instead of bordered cards
- Flat icon buttons with an accent "active" state; tool strip shows the
  shortcut letter and the current layer color; single-key tools V/L/B/R/C
  (not while typing in a field)
- Compact number fields; shape panel with editable position, size and layer,
  layer color and an eraser switch; point X/Y on one row
- Tree rows: visibility eye button, icon, color swatch, name, count
- Menus rounded with accent highlight; tree selection soft accent
- Status bar: position, tool, selection, help, zoom slider with percent and
  fit; zoom buttons/wheel zoom around the view center/mouse pointer
- Bottom bar shows the generated ASSA code next to Cancel/OK

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Background toolbar button used a MenuFlyout whose items were set in
its Opening event, which opened as an empty sliver. The menu is now built
on click and opened under the button, like the canvas menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…raw-ui-improvements-bf9ccd

ASSA draw: menus, new layout, SVG import, undo/redo, scale/rotate, line/curve, backgrounds
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T06:56:59.224466Z c4113e5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pdjdev
pdjdev merged commit e9f61a7 into build/osx Oct 10, 2026
1 check failed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c4113e58b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1377 to +1379
var isItalic = spanStyle.Italic && !parentStyle.Italic;
var isBold = spanStyle.Bold && !parentStyle.Bold;
var isUnderlined = spanStyle.Underline && !parentStyle.Underline;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit normal styling in nested TTML spans

When a paragraph or outer span enables italic, bold, or underline and a nested span explicitly disables it (for example, <p tts:fontStyle="italic">a<span tts:fontStyle="normal">b</span></p>), these checks only emit tags for false-to-true transitions. The outer <i> therefore remains open around b, and the explicit normal override is lost during import. Emit the corresponding close/reopen tags for true-to-false transitions as well.

Useful? React with 👍 / 👎.

Comment on lines +185 to +188
if (sampleRate == null)
{
File.Move(cleanedFileName, fileName, overwrite: true);
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate cleaned WAV output before replacing the reference

When sampleRate is null, this path overwrites the valid reference solely because the Sidon output file exists. Sidon can create a header-only WAV when it produces no samples; the resampling branch already treats files of 44 bytes or less as failures, but this branch replaces the original with that unusable file and reports success. Apply the same nonempty-audio validation before moving the cleaned file so best-effort cleaning can fall back to the original reference.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.