diff --git a/src/audio_display.cpp b/src/audio_display.cpp index 4240c4689c..4a0f467bd9 100644 --- a/src/audio_display.cpp +++ b/src/audio_display.cpp @@ -911,34 +911,61 @@ void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir) void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime) { - std::vector labels; - controller->GetTimingController()->GetLabels(updtime, labels); - if (labels.empty()) return; - - wxDCFontChanger fc(dc); - wxFont font = dc.GetFont(); - font.SetWeight(wxFONTWEIGHT_BOLD); - fc.Set(font); - dc.SetTextForeground(*wxWHITE); - for (auto const& label : labels) - { - wxSize extent = dc.GetTextExtent(label.text); - int left = RelativeXFromTime(label.range.begin()); - int width = AbsoluteXFromTime(label.range.length()); - - // If it doesn't fit, truncate - if (width < extent.GetWidth()) - { - dc.SetClippingRegion(left, audio_top + 4, width, extent.GetHeight()); - dc.DrawText(label.text, left, audio_top + 4); - dc.DestroyClippingRegion(); - } - // Otherwise center in the range - else - { - dc.DrawText(label.text, left + (width - extent.GetWidth()) / 2, audio_top + 4); - } - } + std::vector labels; + controller->GetTimingController()->GetLabels(updtime, labels); + if (labels.empty()) return; + + wxDCFontChanger fc(dc); + wxFont font = dc.GetFont(); + font.SetWeight(wxFONTWEIGHT_BOLD); + fc.Set(font); + dc.SetTextForeground(*wxWHITE); + + for (auto const& label : labels) + { + wxString text = label.text; + wxArrayString lines; + + // Split the text into lines based on \n and \N + wxString current_line; + for (size_t i = 0; i < text.length(); ++i) { + if (text[i] == '\\' && (i + 1 < text.length()) && (text[i + 1] == 'n' || text[i + 1] == 'N')) { + lines.Add(current_line); + current_line.Clear(); + i++; // Skip the 'n' or 'N' + } else { + current_line += text[i]; + } + } + lines.Add(current_line); + + int left = RelativeXFromTime(label.range.begin()); + int width = AbsoluteXFromTime(label.range.length()); + int current_y = audio_top + 4; + int line_height = dc.GetTextExtent("A").GetHeight(); // Approximate line height + + for (size_t i = 0; i < lines.Count(); ++i) { + wxString line = lines[i]; + wxSize line_extent = dc.GetTextExtent(line); + + // Truncate if it doesn't fit + if (width < line_extent.GetWidth()) + { + wxString truncated_line = line; + while (width < dc.GetTextExtent(truncated_line + "...").GetWidth() && truncated_line.length() > 0) { + truncated_line = truncated_line.Left(truncated_line.length() - 1); + } + truncated_line += "..."; + dc.DrawText(truncated_line, left, current_y); + } + else + { + // Center the line + dc.DrawText(line, left + (width - line_extent.GetWidth()) / 2, current_y); + } + current_y += line_height; + } + } } void AudioDisplay::PaintTrackCursor(wxDC &dc) { diff --git a/src/audio_timing_dialogue.cpp b/src/audio_timing_dialogue.cpp index f394f1b883..5387dcff69 100644 --- a/src/audio_timing_dialogue.cpp +++ b/src/audio_timing_dialogue.cpp @@ -307,6 +307,9 @@ class AudioTimingControllerDialogue final : public AudioTimingController { /// All audio markers for active and inactive lines, sorted by position std::vector markers; + // All audio labels for active and inactive lines + std::vector labels; + /// Marker provider for video keyframes AudioMarkerProviderKeyframes keyframes_provider; @@ -389,7 +392,7 @@ class AudioTimingControllerDialogue final : public AudioTimingController { // AudioTimingController interface void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const override; - void GetLabels(TimeRange const& range, std::vector &out) const override { } + void GetLabels(TimeRange const& range, std::vector& out) const override; void Next(NextMode mode) override; void Prev() override; void Revert() override; @@ -471,6 +474,42 @@ void AudioTimingControllerDialogue::GetRenderingStyles(AudioRenderingStyleRanges line.GetStyleRange(&ranges); } +void AudioTimingControllerDialogue::GetLabels(TimeRange const& range, std::vector& out) const { + // Add label for the active line + AssDialogue* activeLine = context->selectionController->GetActiveLine(); + if (activeLine && !activeLine->Comment) { + TimeRange lineRange(activeLine->Start, activeLine->End); + if (range.overlaps(lineRange)) { + AudioLabel activeLabel{activeLine->GetStrippedText().c_str(), lineRange}; + out.push_back(activeLabel); + } + } + + // Add labels for selected lines + for (auto& line : selected_lines) { + AssDialogue* selectedLine = line.GetLine(); + if (selectedLine && !selectedLine->Comment) { + TimeRange lineRange(selectedLine->Start, selectedLine->End); + if (range.overlaps(lineRange)) { + AudioLabel selectedLabel{selectedLine->GetStrippedText().c_str(), lineRange}; + out.push_back(selectedLabel); + } + } + } + + // Add labels for inactive lines + for (auto& line : inactive_lines) { + AssDialogue* inactiveLine = line.GetLine(); + if (inactiveLine && !inactiveLine->Comment) { + TimeRange lineRange(inactiveLine->Start, inactiveLine->End); + if (range.overlaps(lineRange)) { + AudioLabel inactiveLabel{inactiveLine->GetStrippedText().c_str(), lineRange}; + out.push_back(inactiveLabel); + } + } + } +} + void AudioTimingControllerDialogue::Next(NextMode mode) { if (mode == TIMING_UNIT)