diff --git a/src/auto4_base.cpp b/src/auto4_base.cpp index 5a0f442080..a6def6681d 100644 --- a/src/auto4_base.cpp +++ b/src/auto4_base.cpp @@ -215,6 +215,7 @@ namespace Automation4 { wxWindow *ww = config_dialog->CreateWindow(&w); // generate actual dialog contents s->Add(ww, 0, wxALL, 5); // add contents to dialog w.SetSizerAndFit(s); + w.SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); w.CenterOnParent(); w.ShowModal(); }); diff --git a/src/base_grid.cpp b/src/base_grid.cpp index 1afd6e29d0..da575d7361 100644 --- a/src/base_grid.cpp +++ b/src/base_grid.cpp @@ -529,7 +529,9 @@ void BaseGrid::OnMouseEvent(wxMouseEvent &event) { if (event.GetWheelRotation() != 0) { if (ForwardMouseWheelEvent(this, event)) { int step = shift ? h / lineHeight - 2 : 3; - ScrollTo(yPos - step * event.GetWheelRotation() / event.GetWheelDelta()); + scrollWheelProgress += event.GetWheelRotation(); + ScrollTo(yPos - step * (scrollWheelProgress / event.GetWheelDelta())); + scrollWheelProgress %= event.GetWheelDelta(); } return; } diff --git a/src/base_grid.h b/src/base_grid.h index 366189588c..2f28a21dcf 100644 --- a/src/base_grid.h +++ b/src/base_grid.h @@ -46,6 +46,7 @@ class BaseGrid final : public wxWindow { std::vector connections; int lineHeight = 1; ///< Height of a line in pixels in the current font bool holding = false; ///< Is a drag selection in process? + int scrollWheelProgress = 0; ///< How close we are to reaching a full mouse wheel step wxFont font; ///< Current grid font wxScrollBar *scrollBar; ///< The grid's scrollbar bool byFrame = false; ///< Should times be displayed as frame numbers diff --git a/src/dialog_selection.cpp b/src/dialog_selection.cpp index 2adfa764cd..1f821c80a4 100644 --- a/src/dialog_selection.cpp +++ b/src/dialog_selection.cpp @@ -51,7 +51,7 @@ class DialogSelection final : public wxDialog { wxRadioBox *dialogue_field; ///< Which dialogue field to look at wxRadioBox *match_mode; - void Process(wxCommandEvent&); + void Process(wxCommandEvent& event); /// Dialogue/Comment check handler to ensure at least one is always checked /// @param chk The checkbox to check if both are clear @@ -150,7 +150,7 @@ wxDialog (c->parent, -1, _("Select"), wxDefaultPosition, wxDefaultSize, wxCAPTIO main_sizer->Add(selection_change_type = new wxRadioBox(this, -1, _("Action"), wxDefaultPosition, wxDefaultSize, 4, actions, 1), main_flags); } - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL | wxHELP), main_flags); + main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL | wxAPPLY | wxHELP), main_flags); SetSizerAndFit(main_sizer); CenterOnParent(); @@ -165,6 +165,7 @@ wxDialog (c->parent, -1, _("Select"), wxDefaultPosition, wxDefaultSize, wxCAPTIO match_mode->SetSelection(OPT_GET("Tool/Select Lines/Mode")->GetInt()); Bind(wxEVT_BUTTON, &DialogSelection::Process, this, wxID_OK); + Bind(wxEVT_BUTTON, &DialogSelection::Process, this, wxID_APPLY); Bind(wxEVT_BUTTON, std::bind(&HelpButton::OpenPage, "Select Lines"), wxID_HELP); apply_to_comments->Bind(wxEVT_CHECKBOX, std::bind(&DialogSelection::OnDialogueCheckbox, this, apply_to_dialogue)); apply_to_dialogue->Bind(wxEVT_CHECKBOX, std::bind(&DialogSelection::OnDialogueCheckbox, this, apply_to_comments)); @@ -181,7 +182,7 @@ DialogSelection::~DialogSelection() { OPT_SET("Tool/Select Lines/Match/Comment")->SetBool(apply_to_comments->IsChecked()); } -void DialogSelection::Process(wxCommandEvent&) { +void DialogSelection::Process(wxCommandEvent& event) { std::set matches; try { @@ -192,7 +193,7 @@ void DialogSelection::Process(wxCommandEvent&) { dialogue_field->GetSelection(), con->ass.get()); } catch (agi::Exception const&) { - Close(); + if (event.GetId() == wxID_OK) Close(); return; } @@ -242,7 +243,7 @@ void DialogSelection::Process(wxCommandEvent&) { new_active = *new_sel.begin(); con->selectionController->SetSelectionAndActive(std::move(new_sel), new_active); - Close(); + if (event.GetId() == wxID_OK) Close(); } void DialogSelection::OnDialogueCheckbox(wxCheckBox *chk) { diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index 318f8d3eef..d6895bf903 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -389,6 +389,7 @@ "Syntax" : true }, "Provider" : "libass", + "Show Original": false, "Time Edit" : { "Insert Mode" : true } diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json index 59f2ed05f5..54dff1b0b4 100644 --- a/src/libresrc/osx/default_config.json +++ b/src/libresrc/osx/default_config.json @@ -389,6 +389,7 @@ "Syntax" : true }, "Provider" : "libass", + "Show Original": false, "Time Edit" : { "Insert Mode" : true } diff --git a/src/mkv_wrap.cpp b/src/mkv_wrap.cpp index 7c0de16f1c..326c33bc63 100644 --- a/src/mkv_wrap.cpp +++ b/src/mkv_wrap.cpp @@ -114,18 +114,45 @@ struct MkvStdIO final : InputStream { } }; -static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *input, bool srt, double totalTime, AssParser *parser) { +static bool read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *input, bool srt, double totalTime, AssParser *parser, CompressedStream *cs) { std::vector> subList; // Load blocks uint64_t startTime, endTime, filePos; unsigned int rt, frameSize, frameFlags; + std::vector uncompBuf(cs ? 256 : 0); + while (mkv_ReadFrame(file, 0, &rt, &startTime, &endTime, &filePos, &frameSize, &frameFlags) == 0) { - if (ps->IsCancelled()) return; + if (ps->IsCancelled()) return true; if (frameSize == 0) continue; - const std::string_view readBuf(input->file.read(filePos, frameSize), frameSize); + std::string_view readBuf; + + if (cs) { + cs_NextFrame(cs, filePos, frameSize); + int bytesRead = 0; + + int res; + do { + res = cs_ReadData(cs, &uncompBuf[bytesRead], uncompBuf.size() - bytesRead); + if (res == -1) { + const char *err = cs_GetLastError(cs); + if (!err) err = "Unknown error"; + ps->Log("Failed to decompress subtitles: " + std::string(err)); + return false; + } + + bytesRead += res; + + if (bytesRead >= uncompBuf.size()) + uncompBuf.resize(2 * uncompBuf.size()); + } while (res != 0); + + readBuf = std::string_view(&uncompBuf[0], bytesRead); + } else { + readBuf = std::string_view(input->file.read(filePos, frameSize), frameSize); + } // Get start and end times int64_t timecodeScaleLow = 1000000; @@ -167,6 +194,7 @@ static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO * sort(begin(subList), end(subList)); for (auto order_value_pair : subList) parser->AddLine(order_value_pair.second); + return true; } void MatroskaWrapper::GetSubtitles(std::filesystem::path const& filename, AssFile *target) { @@ -183,7 +211,7 @@ void MatroskaWrapper::GetSubtitles(std::filesystem::path const& filename, AssFil // Find tracks for (auto track : boost::irange(0u, tracks)) { auto trackInfo = mkv_GetTrackInfo(file, track); - if (trackInfo->Type != 0x11 || trackInfo->CompEnabled) continue; + if (trackInfo->Type != 0x11) continue; // Known subtitle format std::string CodecID(trackInfo->CodecID); @@ -239,6 +267,13 @@ void MatroskaWrapper::GetSubtitles(std::filesystem::path const& filename, AssFil parser.AddLine("[Events]"); + agi::scoped_holder cs(nullptr, cs_Destroy); + if (trackInfo->CompEnabled) { + cs = cs_Create(file, trackToRead, err, sizeof(err)); + if (!cs) + throw MatroskaException(err); + } + // Read timecode scale auto segInfo = mkv_GetFileInfo(file); int64_t timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale; @@ -246,7 +281,11 @@ void MatroskaWrapper::GetSubtitles(std::filesystem::path const& filename, AssFil // Progress bar auto totalTime = double(segInfo->Duration) / timecodeScale; DialogProgress progress(nullptr, _("Parsing Matroska"), _("Reading subtitles from Matroska file.")); - progress.Run([&](agi::ProgressSink *ps) { read_subtitles(ps, file, &input, srt, totalTime, &parser); }); + bool result; + progress.Run([&](agi::ProgressSink *ps) { result = read_subtitles(ps, file, &input, srt, totalTime, &parser, cs); }); + + if (!result) + throw MatroskaException("Failed to read subtitles"); } bool MatroskaWrapper::HasSubtitles(std::filesystem::path const& filename) { @@ -261,7 +300,7 @@ bool MatroskaWrapper::HasSubtitles(std::filesystem::path const& filename) { for (auto track : boost::irange(0u, tracks)) { auto trackInfo = mkv_GetTrackInfo(file, track); - if (trackInfo->Type == 0x11 && !trackInfo->CompEnabled) { + if (trackInfo->Type == 0x11) { std::string CodecID(trackInfo->CodecID); if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") return true; diff --git a/src/subs_edit_box.cpp b/src/subs_edit_box.cpp index b1b8d92e87..3dfd3199ff 100644 --- a/src/subs_edit_box.cpp +++ b/src/subs_edit_box.cpp @@ -242,6 +242,12 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context) context->textSelectionController->SetControl(edit_ctrl); edit_ctrl->SetFocus(); + + bool show_original = OPT_GET("Subtitle/Show Original")->GetBool(); + if (show_original) { + split_box->SetValue(true); + DoOnSplit(true); + } } SubsEditBox::~SubsEditBox() { @@ -574,15 +580,22 @@ void SubsEditBox::SetControlsState(bool state) { } void SubsEditBox::OnSplit(wxCommandEvent&) { + bool show_original = split_box->IsChecked(); + DoOnSplit(show_original); + OPT_SET("Subtitle/Show Original")->SetBool(show_original); +} + +void SubsEditBox::DoOnSplit(bool show_original) { Freeze(); - GetSizer()->Show(secondary_editor, split_box->IsChecked()); - GetSizer()->Show(bottom_sizer, split_box->IsChecked()); + GetSizer()->Show(secondary_editor, show_original); + GetSizer()->Show(bottom_sizer, show_original); Fit(); SetMinSize(GetSize()); - GetParent()->GetSizer()->Layout(); + wxSizer* parent_sizer = GetParent()->GetSizer(); + if (parent_sizer) parent_sizer->Layout(); Thaw(); - if (split_box->IsChecked()) + if (show_original) secondary_editor->SetValue(to_wx(c->initialLineState->GetInitialText())); } diff --git a/src/subs_edit_box.h b/src/subs_edit_box.h index b17eac81f9..eb22b68cf6 100644 --- a/src/subs_edit_box.h +++ b/src/subs_edit_box.h @@ -155,6 +155,7 @@ class SubsEditBox final : public wxPanel { void OnEffectChange(wxCommandEvent &); void OnSize(wxSizeEvent &event); void OnSplit(wxCommandEvent&); + void DoOnSplit(bool show_original); void SetPlaceholderCtrl(wxControl *ctrl, wxString const& value);