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: