From 0e7df1517066782ced8b0f589838a6e00c41a9ee Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 11 Oct 2012 16:46:53 -0700 Subject: [PATCH] Initial implementation of the split editbox --- aegisub/build/Aegisub/Aegisub.vcxproj | 2 + aegisub/build/Aegisub/Aegisub.vcxproj.filters | 9 ++-- aegisub/src/Makefile | 1 + aegisub/src/command/edit.cpp | 46 ++++++++++++++++ aegisub/src/frame_main.cpp | 2 + aegisub/src/include/aegisub/context.h | 2 + aegisub/src/initial_line_state.cpp | 36 +++++++++++++ aegisub/src/initial_line_state.h | 36 +++++++++++++ aegisub/src/subs_edit_box.cpp | 54 +++++++++++++++++-- aegisub/src/subs_edit_box.h | 6 +++ 10 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 aegisub/src/initial_line_state.cpp create mode 100644 aegisub/src/initial_line_state.h diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj b/aegisub/build/Aegisub/Aegisub.vcxproj index be0a770e1..77582ab91 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj +++ b/aegisub/build/Aegisub/Aegisub.vcxproj @@ -187,6 +187,7 @@ + @@ -450,6 +451,7 @@ + diff --git a/aegisub/build/Aegisub/Aegisub.vcxproj.filters b/aegisub/build/Aegisub/Aegisub.vcxproj.filters index 7fd87b4f9..4beabf456 100644 --- a/aegisub/build/Aegisub/Aegisub.vcxproj.filters +++ b/aegisub/build/Aegisub/Aegisub.vcxproj.filters @@ -678,18 +678,18 @@ Features\Autosave - ASS - Preferences - Features\Search-replace + + Utilities + @@ -1238,6 +1238,9 @@ Features\Search-replace + + Utilities + diff --git a/aegisub/src/Makefile b/aegisub/src/Makefile index 2567021ad..362ba9cf9 100644 --- a/aegisub/src/Makefile +++ b/aegisub/src/Makefile @@ -204,6 +204,7 @@ SRC += \ help_button.cpp \ hotkey.cpp \ hotkey_data_view_model.cpp \ + initial_line_state.cpp \ kana_table.cpp \ main.cpp \ menu.cpp \ diff --git a/aegisub/src/command/edit.cpp b/aegisub/src/command/edit.cpp index 547ede1f1..267f6508f 100644 --- a/aegisub/src/command/edit.cpp +++ b/aegisub/src/command/edit.cpp @@ -53,6 +53,7 @@ #include "../dialog_paste_over.h" #include "../dialog_search_replace.h" #include "../include/aegisub/context.h" +#include "../initial_line_state.h" #include "../options.h" #include "../search_replace_engine.h" #include "../subs_edit_ctrl.h" @@ -918,6 +919,48 @@ struct edit_undo : public Command { } }; +struct edit_revert : public Command { + CMD_NAME("edit/revert") + STR_DISP("Revert") + STR_MENU("Revert") + STR_HELP("Revert the active line to its initial state") + + void operator()(agi::Context *c) { + AssDialogue *line = c->selectionController->GetActiveLine(); + line->Text = c->initialLineState->GetInitialText(); + c->ass->Commit(_("revert line"), AssFile::COMMIT_DIAG_TEXT, -1, line); + } +}; + +struct edit_clear : public Command { + CMD_NAME("edit/clear") + STR_DISP("Clear") + STR_MENU("Clear") + STR_HELP("Clear the current line's text") + + void operator()(agi::Context *c) { + AssDialogue *line = c->selectionController->GetActiveLine(); + line->Text = ""; + c->ass->Commit(_("clear line"), AssFile::COMMIT_DIAG_TEXT, -1, line); + } +}; + +struct edit_insert_original : public Command { + CMD_NAME("edit/insert_original") + STR_DISP("Insert Original") + STR_MENU("Insert Original") + STR_HELP("Insert the original line text at the cursor") + + void operator()(agi::Context *c) { + AssDialogue *line = c->selectionController->GetActiveLine(); + int sel_start = c->textSelectionController->GetSelectionStart(); + int sel_end = c->textSelectionController->GetSelectionEnd(); + + line->Text = line->Text.Left(sel_start) + c->initialLineState->GetInitialText() + line->Text.Mid(sel_end); + c->ass->Commit(_("insert original"), AssFile::COMMIT_DIAG_TEXT, -1, line); + } +}; + } /// @} @@ -949,5 +992,8 @@ namespace cmd { reg(new edit_style_strikeout); reg(new edit_redo); reg(new edit_undo); + reg(new edit_revert); + reg(new edit_insert_original); + reg(new edit_clear); } } diff --git a/aegisub/src/frame_main.cpp b/aegisub/src/frame_main.cpp index e16f1a968..d5ee8fc7d 100644 --- a/aegisub/src/frame_main.cpp +++ b/aegisub/src/frame_main.cpp @@ -61,6 +61,7 @@ #include "dialog_manager.h" #include "dialog_version_check.h" #include "help_button.h" +#include "initial_line_state.h" #include "libresrc/libresrc.h" #include "main.h" #include "options.h" @@ -377,6 +378,7 @@ void FrameMain::InitContents() { context->subsGrid = SubsGrid = new SubtitlesGrid(Panel, context.get()); context->selectionController = context->subsGrid; context->search = new SearchReplaceEngine(context.get()); + context->initialLineState = new InitialLineState(context.get()); StartupLog("Create video box"); videoBox = new VideoBox(Panel, false, context.get()); diff --git a/aegisub/src/include/aegisub/context.h b/aegisub/src/include/aegisub/context.h index 794203f51..9ed70bf48 100644 --- a/aegisub/src/include/aegisub/context.h +++ b/aegisub/src/include/aegisub/context.h @@ -5,6 +5,7 @@ class AssDialogue; class AudioKaraoke; class DialogManager; class SearchReplaceEngine; +class InitialLineState; template class SelectionController; class SubsTextEditCtrl; class SubtitlesGrid; @@ -20,6 +21,7 @@ struct Context { // Models AssFile *ass; Automation4::ScriptManager *local_scripts; + InitialLineState *initialLineState; // Controllers AudioController *audioController; diff --git a/aegisub/src/initial_line_state.cpp b/aegisub/src/initial_line_state.cpp new file mode 100644 index 000000000..e8837b847 --- /dev/null +++ b/aegisub/src/initial_line_state.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "config.h" + +#include "initial_line_state.h" + +#include "ass_dialogue.h" +#include "include/aegisub/context.h" +#include "selection_controller.h" + +InitialLineState::InitialLineState(agi::Context *c) +: active_line_connection(c->selectionController->AddActiveLineListener(&InitialLineState::OnActiveLineChanged, this)) +{ + OnActiveLineChanged(c->selectionController->GetActiveLine()); +} + +void InitialLineState::OnActiveLineChanged(AssDialogue *new_line) { + if (new_line) + initial_text = new_line->Text; + else + initial_text.clear(); + + InitialStateChanged(initial_text); +} diff --git a/aegisub/src/initial_line_state.h b/aegisub/src/initial_line_state.h new file mode 100644 index 000000000..1bfa6ea3c --- /dev/null +++ b/aegisub/src/initial_line_state.h @@ -0,0 +1,36 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#ifndef AGI_PRE +#include +#endif + +#include + +namespace agi { struct Context; } +class AssDialogue; + +class InitialLineState { + agi::signal::Connection active_line_connection; + wxString initial_text; + + agi::signal::Signal InitialStateChanged; + void OnActiveLineChanged(AssDialogue *new_line); + +public: + InitialLineState(agi::Context *c); + + wxString GetInitialText() const { return initial_text; } + DEFINE_SIGNAL_ADDERS(InitialStateChanged, AddChangeListener); +}; diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index 9724a35e4..7d7d070d6 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -55,6 +55,7 @@ #include "compat.h" #include "include/aegisub/context.h" #include "include/aegisub/hotkey.h" +#include "initial_line_state.h" #include "libresrc/libresrc.h" #include "options.h" #include "placeholder_ctrl.h" @@ -166,17 +167,33 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context) by_frame = MakeRadio(_("F&rame"), false, _("Time by frame number")); by_frame->Enable(false); - // Text editor - edit_ctrl = new SubsTextEditCtrl(this, wxSize(300,50), wxBORDER_SUNKEN, c); - edit_ctrl->Bind(wxEVT_CHAR_HOOK, &SubsEditBox::OnKeyDown, this); - Bind(wxEVT_CHAR_HOOK, &SubsEditBox::OnKeyDown, this); + split_box = new wxCheckBox(this,-1,_("Split")); + split_box->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &SubsEditBox::OnSplit, this); + middle_right_sizer->Add(split_box, wxSizerFlags().Center().Left()); // Main sizer wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(top_sizer,0,wxEXPAND | wxALL,3); main_sizer->Add(middle_left_sizer,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,3); main_sizer->Add(middle_right_sizer,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,3); + + // Text editor + edit_ctrl = new SubsTextEditCtrl(this, wxSize(300,50), wxBORDER_SUNKEN, c); + edit_ctrl->Bind(wxEVT_CHAR_HOOK, &SubsEditBox::OnKeyDown, this); + + secondary_editor = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxSize(300,50), wxBORDER_SUNKEN | wxTE_MULTILINE); + secondary_editor->Enable(false); + + main_sizer->Add(secondary_editor,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,3); main_sizer->Add(edit_ctrl,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,3); + main_sizer->Hide(secondary_editor); + + bottom_sizer = new wxBoxSizer(wxHORIZONTAL); + bottom_sizer->Add(MakeBottomButton("edit/revert")); + bottom_sizer->Add(MakeBottomButton("edit/clear")); + bottom_sizer->Add(MakeBottomButton("edit/insert_original")); + main_sizer->Add(bottom_sizer); + main_sizer->Hide(bottom_sizer); SetSizerAndFit(main_sizer); @@ -187,6 +204,7 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context) Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &SubsEditBox::OnLayerEnter, this, layer->GetId()); Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &SubsEditBox::OnCommentChange, this, comment_box->GetId()); + Bind(wxEVT_CHAR_HOOK, &SubsEditBox::OnKeyDown, this); Bind(wxEVT_SIZE, &SubsEditBox::OnSize, this); Bind(wxEVT_TIMER, [=](wxTimerEvent&) { commit_id = -1; }); @@ -197,6 +215,7 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context) connections.push_back(context->videoController->AddTimecodesListener(&SubsEditBox::UpdateFrameTiming, this)); connections.push_back(context->selectionController->AddActiveLineListener(&SubsEditBox::OnActiveLineChanged, this)); connections.push_back(context->selectionController->AddSelectionListener(&SubsEditBox::OnSelectedSetChanged, this)); + connections.push_back(context->initialLineState->AddChangeListener(&SubsEditBox::OnLineInitialTextChanged, this)); textSelectionController.reset(new ScintillaTextSelectionController(edit_ctrl)); context->textSelectionController = textSelectionController.get(); @@ -239,6 +258,15 @@ void SubsEditBox::MakeButton(const char *cmd_name) { btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, std::bind(&SubsEditBox::CallCommand, this, cmd_name)); } +wxButton *SubsEditBox::MakeBottomButton(const char *cmd_name) { + cmd::Command *command = cmd::get(cmd_name); + wxButton *btn = new wxButton(this, -1, command->StrDisplay(c)); + ToolTipManager::Bind(btn, command->StrHelp(), "Subtitle Edit Box", cmd_name); + + btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, std::bind(&SubsEditBox::CallCommand, this, cmd_name)); + return btn; +} + wxComboBox *SubsEditBox::MakeComboBox(wxString const& initial_text, int style, void (SubsEditBox::*handler)(wxCommandEvent&), wxString const& tooltip) { wxString styles[] = { "Default" }; wxComboBox *ctrl = new wxComboBox(this, -1, initial_text, wxDefaultPosition, wxSize(110,-1), 1, styles, style | wxTE_PROCESS_ENTER); @@ -356,6 +384,11 @@ void SubsEditBox::OnSelectedSetChanged(const SubtitleSelection &, const Subtitle initial_times.clear(); } +void SubsEditBox::OnLineInitialTextChanged(wxString const& new_text) { + if (split_box->IsChecked()) + secondary_editor->SetValue(new_text); +} + void SubsEditBox::UpdateFrameTiming(agi::vfr::Framerate const& fps) { if (fps.IsLoaded()) { by_frame->Enable(true); @@ -491,6 +524,19 @@ void SubsEditBox::SetControlsState(bool state) { } } +void SubsEditBox::OnSplit(wxCommandEvent&) { + Freeze(); + GetSizer()->Show(secondary_editor, split_box->IsChecked()); + GetSizer()->Show(bottom_sizer, split_box->IsChecked()); + Fit(); + SetMinSize(GetSize()); + GetParent()->GetSizer()->Layout(); + Thaw(); + + if (split_box->IsChecked()) + secondary_editor->SetValue(c->initialLineState->GetInitialText()); +} + void SubsEditBox::OnStyleChange(wxCommandEvent &) { SetSelectedRows(&AssDialogue::Style, boost::flyweight(style_box->GetValue()), _("style change"), AssFile::COMMIT_DIAG_META); } diff --git a/aegisub/src/subs_edit_box.h b/aegisub/src/subs_edit_box.h index 0b6d52e62..f6dc58715 100644 --- a/aegisub/src/subs_edit_box.h +++ b/aegisub/src/subs_edit_box.h @@ -104,10 +104,12 @@ class SubsEditBox : public wxPanel { wxRadioButton *by_time; wxRadioButton *by_frame; wxTextCtrl *char_count; + wxCheckBox *split_box; wxSizer *top_sizer; wxSizer *middle_right_sizer; wxSizer *middle_left_sizer; + wxSizer *bottom_sizer; void SetControlsState(bool state); /// @brief Update times of selected lines @@ -138,6 +140,7 @@ class SubsEditBox : public wxPanel { wxTextCtrl *MakeMarginCtrl(wxString const& tooltip, int margin, wxString const& commit_msg); TimeEdit *MakeTimeCtrl(wxString const& tooltip, TimeField field); void MakeButton(const char *cmd_name); + wxButton *MakeBottomButton(const char *cmd_name); wxComboBox *MakeComboBox(wxString const& initial_text, int style, void (SubsEditBox::*handler)(wxCommandEvent&), wxString const& tooltip); wxRadioButton *MakeRadio(wxString const& text, bool start, wxString const& tooltip); @@ -146,6 +149,7 @@ class SubsEditBox : public wxPanel { void OnActiveLineChanged(AssDialogue *new_line); void OnSelectedSetChanged(const SubtitleSelection &, const SubtitleSelection &); + void OnLineInitialTextChanged(wxString const& new_text); void OnFrameTimeRadio(wxCommandEvent &event); void OnStyleChange(wxCommandEvent &event); @@ -154,6 +158,7 @@ class SubsEditBox : public wxPanel { void OnCommentChange(wxCommandEvent &); void OnEffectChange(wxCommandEvent &); void OnSize(wxSizeEvent &event); + void OnSplit(wxCommandEvent&); void SetPlaceholderCtrl(wxControl *ctrl, wxString const& value); @@ -191,6 +196,7 @@ class SubsEditBox : public wxPanel { void CallCommand(const char *cmd_name); SubsTextEditCtrl *edit_ctrl; + wxTextCtrl *secondary_editor; agi::scoped_ptr textSelectionController; public: