From fc46b25726b31390040761c900295889e6d2af85 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 27 Jul 2011 05:36:15 +0000 Subject: [PATCH] Rewrite the translation assisant and make it work again Originally committed to SVN as r5519. --- aegisub/src/command/tool.cpp | 80 ++- aegisub/src/dialog_translation.cpp | 637 ++++++++--------------- aegisub/src/dialog_translation.h | 158 ++---- aegisub/src/include/aegisub/context.h | 2 + aegisub/src/libresrc/default_config.json | 7 + aegisub/src/libresrc/default_hotkey.json | 14 +- 6 files changed, 342 insertions(+), 556 deletions(-) diff --git a/aegisub/src/command/tool.cpp b/aegisub/src/command/tool.cpp index ac3bf40fb..7a1f78a98 100644 --- a/aegisub/src/command/tool.cpp +++ b/aegisub/src/command/tool.cpp @@ -228,12 +228,81 @@ struct tool_translation_assistant : public Command { void operator()(agi::Context *c) { c->videoController->Stop(); - int start = c->subsGrid->GetFirstSelRow(); - if (start == -1) start = 0; - DialogTranslation(c, start, true).ShowModal(); + DialogTranslation d(c); + c->translationAssistant = &d; + d.ShowModal(); + c->translationAssistant = 0; + } +}; + +struct tool_translation_assistant_validator : public Command { + CMD_TYPE(COMMAND_VALIDATE) + + bool Validate(agi::Context *c) { + return !!c->translationAssistant; + } +}; + +/// Commit changes and move to the next line. +struct tool_translation_assistant_commit : public tool_translation_assistant_validator { + CMD_NAME("tool/translation_assistant/commit") + STR_MENU("&Accept changes") + STR_DISP("Accept changes") + STR_HELP("Commit changes and move to the next line.") + + void operator()(agi::Context *c) { + c->translationAssistant->Commit(true); + } +}; + +/// Commit changes and stay on the current line. +struct tool_translation_assistant_preview : public tool_translation_assistant_validator { + CMD_NAME("tool/translation_assistant/preview") + STR_MENU("&Preview changes") + STR_DISP("Preview changes") + STR_HELP("Commit changes and stay on the current line.") + + void operator()(agi::Context *c) { + c->translationAssistant->Commit(false); + } +}; + +/// Move to the next line without committing changes. +struct tool_translation_assistant_next : public tool_translation_assistant_validator { + CMD_NAME("tool/translation_assistant/next") + STR_MENU("&Next line") + STR_DISP("Next line") + STR_HELP("Move to the next line without committing changes.") + + void operator()(agi::Context *c) { + c->translationAssistant->NextBlock(); + } +}; + +/// Move to the previous line without committing changes. +struct tool_translation_assistant_prev : public tool_translation_assistant_validator { + CMD_NAME("tool/translation_assistant/prev") + STR_MENU("&Prev line") + STR_DISP("Prev line") + STR_HELP("Move to the previous line without committing changes.") + + void operator()(agi::Context *c) { + c->translationAssistant->PrevBlock(); } }; } + +/// Insert the untranslated text. +struct tool_translation_assistant_insert : public tool_translation_assistant_validator { + CMD_NAME("tool/translation_assistant/insert_original") + STR_MENU("&Insert Original") + STR_DISP("Insert Original") + STR_HELP("Insert the untranslated text.") + + void operator()(agi::Context *c) { + c->translationAssistant->InsertOriginal(); + } +}; /// @} namespace cmd { @@ -254,5 +323,10 @@ namespace cmd { reg(new tool_assdraw); } #endif + reg(new tool_translation_assistant_commit); + reg(new tool_translation_assistant_preview); + reg(new tool_translation_assistant_next); + reg(new tool_translation_assistant_prev); + reg(new tool_translation_assistant_insert); } } diff --git a/aegisub/src/dialog_translation.cpp b/aegisub/src/dialog_translation.cpp index 988f51d61..4d4010394 100644 --- a/aegisub/src/dialog_translation.cpp +++ b/aegisub/src/dialog_translation.cpp @@ -1,29 +1,16 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2011, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// 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. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// 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. // // Aegisub Project http://www.aegisub.org/ // @@ -34,14 +21,9 @@ /// @ingroup tools_ui /// - -/////////// -// Headers #include "config.h" -#ifndef AGI_PRE -#include -#endif +#include "dialog_translation.h" #include "include/aegisub/context.h" #include "include/aegisub/hotkey.h" @@ -49,443 +31,238 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "audio_controller.h" -#include "dialog_translation.h" -#include "frame_main.h" +#include "command/command.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "persist_location.h" +#include "scintilla_text_ctrl.h" #include "selection_controller.h" -#include "subs_edit_box.h" -#include "subs_edit_ctrl.h" -#include "subs_grid.h" #include "utils.h" #include "video_context.h" -#include "video_display.h" +#ifndef AGI_PRE +#include +#include +#include +#endif -/// @brief Constructor -/// @param parent -/// @param _subs -/// @param _grid -/// @param startrow -/// @param preview -/// -DialogTranslation::DialogTranslation(agi::Context *c, int startrow, bool preview) -: wxDialog(c->parent, -1, _("Translation Assistant"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX, _T("TranslationAssistant")) -{ - // Set icon - SetIcon(BitmapToIcon(GETIMAGE(translation_toolbutton_24))); - - // Set variables - enablePreview = preview; - main = c->parent; - subs = c->ass; - grid = c->subsGrid; - audio = c->audioController; - video = c->videoController; - - // Translation controls - OrigText = new ScintillaTextCtrl(this,TEXT_ORIGINAL,_T(""),wxDefaultPosition,wxSize(320,80)); - OrigText->SetWrapMode(wxSTC_WRAP_WORD); - OrigText->SetMarginWidth(1,0); - OrigText->StyleSetForeground(1,wxColour(10,60,200)); - OrigText->SetReadOnly(true); - //OrigText->PushEventHandler(new DialogTranslationEvent(this)); - TransText = new ScintillaTextCtrl(this,TEXT_TRANS,_T(""),wxDefaultPosition,wxSize(320,80)); - TransText->SetWrapMode(wxSTC_WRAP_WORD); - TransText->SetMarginWidth(1,0); - TransText->PushEventHandler(new DialogTranslationEvent(this)); - TransText->SetFocus(); - - // Translation box - wxSizer *TranslationSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *OriginalTransSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Original")); - wxSizer *TranslatedSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Translation")); - LineCount = new wxStaticText(this,-1,_("Current line: ?")); - OriginalTransSizer->Add(LineCount,0,wxBOTTOM,5); - OriginalTransSizer->Add(OrigText,1,wxEXPAND,0); - TranslatedSizer->Add(TransText,1,wxEXPAND,0); - TranslationSizer->Add(OriginalTransSizer,1,wxEXPAND,0); - TranslationSizer->Add(TranslatedSizer,1,wxTOP|wxEXPAND,5); - - // Hotkeys - wxSizer *KeysSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Keys")); - wxSizer *KeysInnerSizer = new wxGridSizer(2,0,5); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Accept")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Accept changes"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Preview")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Preview changes"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Prev")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Previous line"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Next")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Next line"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Insert Original")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Insert original"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Play Video")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Play Video"))); -//H KeysInnerSizer->Add(new wxStaticText(this,-1,Hotkeys.GetText(_T("Translation Assistant Play Audio")) + _T(": "))); - KeysInnerSizer->Add(new wxStaticText(this,-1,_("Play Audio"))); - PreviewCheck = new wxCheckBox(this,PREVIEW_CHECK,_("Enable preview")); - PreviewCheck->SetValue(preview); - PreviewCheck->PushEventHandler(new DialogTranslationEvent(this)); - KeysSizer->Add(KeysInnerSizer,0,wxEXPAND,0); - KeysSizer->Add(PreviewCheck,0,wxTOP,5); - - // Tool sizer - wxStaticBoxSizer *ToolSizer = new wxStaticBoxSizer(wxVERTICAL,this, _("Actions")); - wxButton *PlayVideoButton = new wxButton(this,BUTTON_TRANS_PLAY_VIDEO,_("Play Video")); - wxButton *PlayAudioButton = new wxButton(this,BUTTON_TRANS_PLAY_AUDIO,_("Play Audio")); - PlayVideoButton->Enable(video->IsLoaded()); - /// @todo Reinstate this when the audio context is made reachable from here - //PlayAudioButton->Enable(audio->loaded); - ToolSizer->Add(PlayAudioButton,0,wxALL,5); - ToolSizer->Add(PlayVideoButton,0,wxLEFT | wxRIGHT | wxBOTTOM,5); - - // Hotkeys + Tool sizer - wxBoxSizer *HTSizer = new wxBoxSizer(wxHORIZONTAL); - HTSizer->Add(KeysSizer,1,wxRIGHT | wxEXPAND,5); - HTSizer->Add(ToolSizer,0); - - // Button sizer - wxStdDialogButtonSizer *ButtonSizer = new wxStdDialogButtonSizer(); - ButtonSizer->AddButton(new wxButton(this,wxID_CANCEL)); - ButtonSizer->AddButton(new HelpButton(this,_T("Translation Assistant"))); - ButtonSizer->Realize(); - - // General layout - wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); - MainSizer->Add(TranslationSizer,1,wxALL | wxEXPAND,5); - MainSizer->Add(HTSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5); - MainSizer->Add(ButtonSizer,0,wxALIGN_RIGHT | wxLEFT | wxBOTTOM | wxRIGHT,5); - - // Set sizer - SetSizer(MainSizer); - MainSizer->SetSizeHints(this); - - // Position window - if (lastx == -1 && lasty == -1) { - CenterOnParent(); - } else { - Move(lastx, lasty); - } - - // Set subs/grid - JumpToLine(startrow,0); - UpdatePreview(); +static void add_hotkey(wxSizer *sizer, wxWindow *parent, const char *command, const char *text) { + sizer->Add(new wxStaticText(parent, -1, _(text))); + sizer->Add(new wxStaticText(parent, -1, hotkey::get_hotkey_str_first("Translation Assistant", command))); } +DialogTranslation::DialogTranslation(agi::Context *c) +: wxDialog(c->parent, -1, _("Translation Assistant"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX, "TranslationAssistant") +, c(c) +, active_line(c->selectionController->GetActiveLine()) +, cur_block(0) +, line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast())) +, line_number(count_if(c->ass->Line.begin(), find(c->ass->Line.begin(), c->ass->Line.end(), active_line), cast()) + 1) +{ + SetIcon(BitmapToIcon(GETIMAGE(translation_toolbutton_16))); + wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); -/// @brief Jumps to line at block -/// @param n -/// @param block -/// @return -/// -bool DialogTranslation::JumpToLine(int n,int block) { - using std::vector; - AssDialogue *nextLine; - try { - nextLine = grid->GetDialogue(n); - } catch (...) { - return false; - } - if (!nextLine) return false; - current = nextLine; + wxSizer *translation_sizer = new wxBoxSizer(wxVERTICAL); + { + wxSizer *original_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Original")); - // Count blocks - int nblocks = 0; - current->ParseASSTags(); - size_t size_blocks = current->Blocks.size(); - for (size_t i=0;iBlocks.at(i)->GetType() == BLOCK_PLAIN) nblocks++; + line_number_display = new wxStaticText(this, -1, ""); + original_box->Add(line_number_display, 0, wxBOTTOM, 5); + + original_text = new ScintillaTextCtrl(this, -1, "", wxDefaultPosition, wxSize(320, 80)); + original_text->SetWrapMode(wxSTC_WRAP_WORD); + original_text->SetMarginWidth(1, 0); + original_text->StyleSetForeground(1, wxColour(10, 60, 200)); + original_text->SetReadOnly(true); + original_box->Add(original_text, 1, wxEXPAND, 0); + + translation_sizer->Add(original_box, 1, wxEXPAND, 0); } - // Wrap around - if (block == 0xFFFF) block = nblocks-1; - if (block < 0) { - block = 0xFFFF; - n--; - return JumpToLine(n,block); + { + translated_text = new ScintillaTextCtrl(this, -1, "", wxDefaultPosition, wxSize(320, 80)); + translated_text->SetWrapMode(wxSTC_WRAP_WORD); + translated_text->SetMarginWidth(1, 0); + translated_text->SetFocus(); + translated_text->Bind(wxEVT_KEY_DOWN, &DialogTranslation::OnKeyDown, this); + + wxSizer *translated_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Translation")); + translated_box->Add(translated_text, 1, wxEXPAND, 0); + translation_sizer->Add(translated_box, 1, wxTOP|wxEXPAND, 5); } - if (block >= nblocks) { - block = 0; - n++; - return JumpToLine(n,block); + main_sizer->Add(translation_sizer, 1, wxALL | wxEXPAND, 5); + + wxSizer *right_box = new wxBoxSizer(wxHORIZONTAL); + { + wxSizer *hotkey_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Keys")); + + wxSizer *hotkey_grid = new wxGridSizer(2, 0, 5); + add_hotkey(hotkey_grid, this, "tool/translation_assistant/commit", "Accept changes"); + add_hotkey(hotkey_grid, this, "tool/translation_assistant/preview", "Preview changes"); + add_hotkey(hotkey_grid, this, "tool/translation_assistant/prev", "Previous line"); + add_hotkey(hotkey_grid, this, "tool/translation_assistant/next", "Next line"); + add_hotkey(hotkey_grid, this, "tool/translation_assistant/insert_original", "Insert original"); + add_hotkey(hotkey_grid, this, "video/play/line", "Play Video"); + add_hotkey(hotkey_grid, this, "audio/play/selection", "Play Audio"); + hotkey_box->Add(hotkey_grid, 0, wxEXPAND, 0); + + seek_video = new wxCheckBox(this, -1, _("Enable preview")); + seek_video->SetValue(true); + hotkey_box->Add(seek_video, 0, wxTOP, 5); + + right_box->Add(hotkey_box, 1, wxRIGHT | wxEXPAND, 5); } - // Set current - curline = n; - current = grid->GetDialogue(n); - curblock = block; - LineCount->SetLabel(wxString::Format(_("Current line: %i/%i"),curline+1,grid->GetRows())); + { + wxStaticBoxSizer *actions_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Actions")); - // Update grid - grid->BeginBatch(); - grid->SelectRow(curline); - grid->MakeCellVisible(curline,0); - grid->SetActiveLine(current); - grid->EndBatch(); + wxButton *play_audio = new wxButton(this, -1, _("Play Audio")); + play_audio->Enable(c->audioController->IsAudioOpen()); + play_audio->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogTranslation::OnPlayAudioButton, this); + actions_box->Add(play_audio, 0, wxALL, 5); - // Adds blocks - OrigText->SetReadOnly(false); - OrigText->ClearAll(); - AssDialogueBlock *curBlock; - bool found = false; - int pos=-1; - for (vector::iterator cur=current->Blocks.begin();cur!=current->Blocks.end();cur++) { - curBlock = *cur; - if (curBlock->GetType() == BLOCK_PLAIN) { - pos++; - int curLen = OrigText->GetReverseUnicodePosition(OrigText->GetLength()); - OrigText->AppendText(curBlock->text); - if (pos == block) { - OrigText->StartUnicodeStyling(curLen); - OrigText->SetUnicodeStyling(curLen,curBlock->text.Length(),1); - found = true; - } + wxButton *play_video = new wxButton(this, -1, _("Play Video")); + play_video->Enable(c->videoController->IsLoaded()); + play_video->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogTranslation::OnPlayVideoButton, this); + actions_box->Add(play_video, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); + + right_box->Add(actions_box, 0); + } + main_sizer->Add(right_box, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); + + { + wxStdDialogButtonSizer *standard_buttons = new wxStdDialogButtonSizer(); + standard_buttons->AddButton(new wxButton(this, wxID_CANCEL)); + standard_buttons->AddButton(new HelpButton(this, "Translation Assistant")); + standard_buttons->Realize(); + main_sizer->Add(standard_buttons, 0, wxALIGN_RIGHT | wxLEFT | wxBOTTOM | wxRIGHT, 5); + } + + SetSizer(main_sizer); + main_sizer->SetSizeHints(this); + + persist.reset(new PersistLocation(this, "Tool/Translation Assistant")); + + Bind(wxEVT_KEY_DOWN, &DialogTranslation::OnKeyDown, this); + active_line->ParseASSTags(); + UpdateDisplay(); +} + +DialogTranslation::~DialogTranslation() { } + +// Skip over override blocks, comments, and whitespace between blocks +static bool bad_block(AssDialogueBlock *block) { + if (block->GetType() != BLOCK_PLAIN) return true; + wxString text = block->GetText(); + if (text.Trim().Trim(false).empty()) return true; + if (text[0] == '{' && text.Last() == '}') return true; + return false; +} + +bool DialogTranslation::NextBlock() { + do { + if (cur_block == active_line->Blocks.size() - 1) { + c->selectionController->NextLine(); + AssDialogue *new_line = c->selectionController->GetActiveLine(); + if (active_line == new_line || !new_line) return false; + + active_line->ClearBlocks(); + active_line = new_line; + active_line->ParseASSTags(); + cur_block = 0; + ++line_number; } - else if (curBlock->GetType() == BLOCK_OVERRIDE) OrigText->AppendText(_T("{") + curBlock->text + _T("}")); - } - current->ClearBlocks(); - OrigText->SetReadOnly(true); + else + ++cur_block; + } while (bad_block(active_line->Blocks[cur_block])); + UpdateDisplay(); return true; } +bool DialogTranslation::PrevBlock() { + do { + if (cur_block == 0) { + c->selectionController->PrevLine(); + AssDialogue *new_line = c->selectionController->GetActiveLine(); + if (active_line == new_line || !new_line) return false; + active_line->ClearBlocks(); + active_line = new_line; + active_line->ParseASSTags(); + cur_block = active_line->Blocks.size() - 1; + --line_number; + } + else + --cur_block; + } while (bad_block(active_line->Blocks[cur_block])); -/// @brief Updates video preview -/// @return -/// -void DialogTranslation::UpdatePreview () { - if (enablePreview) { - try { - if (video->IsLoaded()) { - AssDialogue *cur = grid->GetDialogue(curline); - video->JumpToTime(cur->Start.GetMS()); + UpdateDisplay(); + return true; +} + +void DialogTranslation::UpdateDisplay() { + line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), line_number, line_count)); + + original_text->SetReadOnly(false); + original_text->ClearAll(); + + for (size_t i = 0; i < active_line->Blocks.size(); ++i) { + AssDialogueBlock *block = active_line->Blocks[i]; + if (block->GetType() == BLOCK_PLAIN) { + int cur_size = original_text->GetReverseUnicodePosition(original_text->GetLength()); + original_text->AppendText(block->text); + if (i == cur_block) { + original_text->StartUnicodeStyling(cur_size); + original_text->SetUnicodeStyling(cur_size, block->text.size(), 1); } } - catch (...) { - return; + else if (block->GetType() == BLOCK_OVERRIDE) + original_text->AppendText("{" + block->text + "}"); + } + + original_text->SetReadOnly(true); + + if (seek_video->IsChecked()) c->videoController->JumpToTime(active_line->Start.GetMS()); + + translated_text->ClearAll(); + translated_text->SetFocus(); +} + +void DialogTranslation::Commit(bool next) { + active_line->Blocks[cur_block]->text = translated_text->GetValue(); + active_line->UpdateText(); + c->ass->Commit(_("translation assistant"), AssFile::COMMIT_TEXT); + + if (next) { + if (!NextBlock()) { + wxMessageBox(_("No more lines to translate.")); + EndModal(1); } } + else { + UpdateDisplay(); + } } -/////////////// -// Event table -BEGIN_EVENT_TABLE(DialogTranslation, wxDialog) - EVT_BUTTON(wxID_CANCEL,DialogTranslation::OnClose) - EVT_BUTTON(BUTTON_TRANS_PLAY_VIDEO,DialogTranslation::OnPlayVideoButton) - EVT_BUTTON(BUTTON_TRANS_PLAY_AUDIO,DialogTranslation::OnPlayAudioButton) -END_EVENT_TABLE() - - -///////////////// -// Event handler - - -/// @brief Constructor -/// @param ctrl -/// -DialogTranslationEvent::DialogTranslationEvent(DialogTranslation *ctrl) { - control = ctrl; -} - -// Event table -BEGIN_EVENT_TABLE(DialogTranslationEvent, wxEvtHandler) - EVT_KEY_DOWN(DialogTranslationEvent::OnTransBoxKey) - EVT_CHECKBOX(PREVIEW_CHECK, DialogTranslationEvent::OnPreviewCheck) -END_EVENT_TABLE() - - -/// @brief Redirects -/// @param event -/// -void DialogTranslationEvent::OnPreviewCheck(wxCommandEvent &event) { control->enablePreview = event.IsChecked(); } - -/// @brief DOCME -/// @param event -/// -void DialogTranslationEvent::OnTransBoxKey(wxKeyEvent &event) { control->OnTransBoxKey(event); } - - - -/// @brief Key pressed event -/// @param event -/// @return -/// -void DialogTranslation::OnTransBoxKey(wxKeyEvent &event) { - if (!hotkey::check("Translation Assistant", event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers())) - event.Skip(); - event.StopPropagation(); - -// H convert below to commands. -/* -#ifdef __APPLE__ - Hotkeys.SetPressed(event.GetKeyCode(),event.m_metaDown,event.m_altDown,event.m_shiftDown); -#else - Hotkeys.SetPressed(event.GetKeyCode(),event.m_controlDown,event.m_altDown,event.m_shiftDown); -#endif - - // Previous - if (Hotkeys.IsPressed(_T("Translation Assistant Prev"))) { - bool ok = JumpToLine(curline,curblock-1); - if (ok) { - TransText->ClearAll(); - TransText->SetFocus(); - } - - UpdatePreview(); - return; - } - - // Next - if (Hotkeys.IsPressed(_T("Translation Assistant Next")) || (Hotkeys.IsPressed(_T("Translation Assistant Accept")) && TransText->GetValue().IsEmpty())) { - bool ok = JumpToLine(curline,curblock+1); - if (ok) { - TransText->ClearAll(); - TransText->SetFocus(); - } - - UpdatePreview(); - return; - } - - // Accept (enter) - if (Hotkeys.IsPressed(_T("Translation Assistant Accept")) || Hotkeys.IsPressed(_T("Translation Assistant Preview"))) { - // Store - AssDialogue *cur = grid->GetDialogue(curline); - cur->ParseASSTags(); - int nblock = -1; - for (unsigned int i=0;iBlocks.size();i++) { - if (cur->Blocks.at(i)->GetType() == BLOCK_PLAIN) nblock++; - if (nblock == curblock) { - cur->Blocks.at(i)->text = TransText->GetValue(); - break; - } - } - - // Update line - cur->UpdateText(); - cur->ClearBlocks(); - subs->Commit(_("translation assistant"), AssFile::COMMIT_TEXT); - UpdatePreview(); - - // Next - if (Hotkeys.IsPressed(_T("Translation Assistant Accept"))) { - // JumpToLine() returns false if the requested line doesn't exist. - // Assume that means we were on the last line. - if (!JumpToLine(curline,curblock+1)) { - wxMessageBox(_("No more lines to translate.")); - EndModal(1); - return; - } - TransText->ClearAll(); - TransText->SetFocus(); - } - else JumpToLine(curline,curblock); - return; - } - - // Insert original text (insert) - if (Hotkeys.IsPressed(_T("Translation Assistant Insert Original"))) { - using std::vector; - AssDialogueBlock *curBlock; - int pos = -1; - current->ParseASSTags(); - for (vector::iterator cur=current->Blocks.begin();cur!=current->Blocks.end();cur++) { - curBlock = *cur; - if (curBlock->GetType() == BLOCK_PLAIN) { - pos++; - if (pos == curblock) { - TransText->AddText(curBlock->text); - } - } - } - current->ClearBlocks(); - return; - } - - // Play video - if (Hotkeys.IsPressed(_T("Translation Assistant Play Video"))) { - if (video->IsLoaded()) { - video->PlayLine(); - TransText->SetFocus(); - } - return; - } - - // Play audio - if (Hotkeys.IsPressed(_T("Translation Assistant Play Audio"))) { - /// @todo Reinstate this when the audio controller is made reachable from here - //if (audio->loaded) { - // audio->Play(current->Start.GetMS(),current->End.GetMS()); - // TransText->SetFocus(); - //} - return; - } - - // Close - if (event.GetKeyCode() == WXK_ESCAPE) EndModal(1); - - // Ignore enter - if (event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER) return; - - // Skip anything else - event.Skip(); -*/ +void DialogTranslation::InsertOriginal() { + translated_text->AddText(active_line->Blocks[cur_block]->GetText()); } - -/// @brief Play video button -/// @param event -/// -void DialogTranslation::OnPlayVideoButton(wxCommandEvent &event) { - video->PlayLine(); - TransText->SetFocus(); +void DialogTranslation::OnKeyDown(wxKeyEvent &evt) { + if (!hotkey::check("Translation Assistant", evt.GetKeyCode(), evt.GetUnicodeKey(), evt.GetModifiers())) + evt.Skip(); + evt.StopPropagation(); } - - -/// @brief Play audio button -/// @param event -/// -void DialogTranslation::OnPlayAudioButton(wxCommandEvent &event) { - audio->PlayRange(SampleRange( - audio->SamplesFromMilliseconds(current->Start.GetMS()), - audio->SamplesFromMilliseconds(current->End.GetMS()))); - TransText->SetFocus(); +void DialogTranslation::OnPlayVideoButton(wxCommandEvent &) { + c->videoController->PlayLine(); + translated_text->SetFocus(); } - - -/// @brief Close -/// @param event -/// -void DialogTranslation::OnClose (wxCommandEvent &event) { - GetPosition(&lastx, &lasty); - TransText->PopEventHandler(true); - PreviewCheck->PopEventHandler(true); - EndModal(0); +void DialogTranslation::OnPlayAudioButton(wxCommandEvent &) { + cmd::call("audio/play/selection", c); + translated_text->SetFocus(); } - - - -/// @brief Minimize -/// @param event -/// -void DialogTranslation::OnMinimize (wxIconizeEvent &event) { - //Iconize(true); - if (main) ((wxFrame*)main)->Iconize(true); - event.Skip(); -} - - - -/// DOCME -int DialogTranslation::lastx = -1; - -/// DOCME -int DialogTranslation::lasty = -1; - - diff --git a/aegisub/src/dialog_translation.h b/aegisub/src/dialog_translation.h index 25019ab99..e8a96a0a8 100644 --- a/aegisub/src/dialog_translation.h +++ b/aegisub/src/dialog_translation.h @@ -1,29 +1,16 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2011, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// 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. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// 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. // // Aegisub Project http://www.aegisub.org/ // @@ -31,118 +18,57 @@ /// @file dialog_translation.h /// @see dialog_translation.cpp -/// @ingroup tools_ui/// +/// @ingroup tools_ui #ifndef AGI_PRE -#include #include -#include #endif +#include + namespace agi { struct Context; } class AssDialogue; -class AssFile; -class AudioController; -class AudioDisplay; +class PersistLocation; class ScintillaTextCtrl; -class SubtitlesGrid; -class VideoContext; +class wxStaticText; +class wxCheckBox; - -/// DOCME /// @class DialogTranslation -/// @brief DOCME +/// @brief Assistant for translating subtitles in one language to another language /// /// DOCME class DialogTranslation : public wxDialog { -private: + agi::Context *c; - /// DOCME - AudioController *audio; + /// The active line + AssDialogue *active_line; + /// Which dialogue block in the active line is currrently being translated + size_t cur_block; - /// DOCME - VideoContext *video; + /// Total number of dialogue lines in the file + size_t line_count; + /// Line number of the currently active line + size_t line_number; - /// DOCME - AssFile *subs; + wxStaticText *line_number_display; + ScintillaTextCtrl *original_text; + ScintillaTextCtrl *translated_text; + wxCheckBox *seek_video; - /// DOCME - SubtitlesGrid *grid; + agi::scoped_ptr persist; - /// DOCME - AssDialogue *current; + void OnPlayAudioButton(wxCommandEvent &); + void OnPlayVideoButton(wxCommandEvent &); + void OnKeyDown(wxKeyEvent &evt); - /// DOCME - wxWindow *main; - - /// DOCME - int curline; - - /// DOCME - int curblock; - - - /// DOCME - wxStaticText *LineCount; - - /// DOCME - ScintillaTextCtrl *OrigText; - - /// DOCME - ScintillaTextCtrl *TransText; - - /// DOCME - wxCheckBox *PreviewCheck; - - void OnMinimize(wxIconizeEvent &event); - void OnPlayAudioButton(wxCommandEvent &event); - void OnPlayVideoButton(wxCommandEvent &event); - void OnClose(wxCommandEvent &event); - - bool JumpToLine(int n,int block); - void UpdatePreview(); - - - /// DOCME - - /// DOCME - static int lastx, lasty; + void UpdateDisplay(); public: + DialogTranslation(agi::Context *context); + ~DialogTranslation(); - /// DOCME - bool enablePreview; - DialogTranslation(agi::Context *context, int startrow=0, bool preview=false); - - void OnTransBoxKey(wxKeyEvent &event); - - DECLARE_EVENT_TABLE() -}; - -/// DOCME -/// @class DialogTranslationEvent -/// @brief DOCME -/// -/// DOCME -class DialogTranslationEvent : public wxEvtHandler { -private: - - /// DOCME - DialogTranslation *control; - - void OnPreviewCheck(wxCommandEvent &event); - void OnTransBoxKey(wxKeyEvent &event); - -public: - DialogTranslationEvent(DialogTranslation *control); - DECLARE_EVENT_TABLE() -}; - -/// Event IDs -enum { - TEXT_ORIGINAL = 1100, - TEXT_TRANS, - PREVIEW_CHECK, - BUTTON_TRANS_PLAY_AUDIO, - BUTTON_TRANS_PLAY_VIDEO + bool NextBlock(); + bool PrevBlock(); + void Commit(bool next); + void InsertOriginal(); }; diff --git a/aegisub/src/include/aegisub/context.h b/aegisub/src/include/aegisub/context.h index a50685888..9b992d531 100644 --- a/aegisub/src/include/aegisub/context.h +++ b/aegisub/src/include/aegisub/context.h @@ -4,6 +4,7 @@ class AudioController; class AssDialogue; class DialogDetachedVideo; class DialogStyling; +class DialogTranslation; template class SelectionController; class SubsEditBox; class SubtitlesGrid; @@ -32,6 +33,7 @@ struct Context { AudioBox *audioBox; DialogDetachedVideo *detachedVideo; DialogStyling *stylingAssistant; + DialogTranslation *translationAssistant; SubsEditBox *editBox; SubtitlesGrid *subsGrid; VideoBox *videoBox; diff --git a/aegisub/src/libresrc/default_config.json b/aegisub/src/libresrc/default_config.json index bfd34d3a8..3b9cc7780 100644 --- a/aegisub/src/libresrc/default_config.json +++ b/aegisub/src/libresrc/default_config.json @@ -374,6 +374,13 @@ "Key Start Before" : 5 } }, + "Translation Assistant" : { + "Last" : { + "X" : -1, + "Y" : -1 + }, + "Maximized" : false + }, "Visual" : { "Always Show": true } diff --git a/aegisub/src/libresrc/default_hotkey.json b/aegisub/src/libresrc/default_hotkey.json index 4949520a7..2edba24b1 100644 --- a/aegisub/src/libresrc/default_hotkey.json +++ b/aegisub/src/libresrc/default_hotkey.json @@ -579,43 +579,43 @@ }, "Translation Assistant" : { - "audio play" : [ + "audio/play/selection" : [ { "modifiers" : [], "key" : "End" } ], - "translation assiatant prev item" : [ + "tool/translation_assistant/prev" : [ { "modifiers" : [], "key" : "PageUp" } ], - "translation assistant commit" : [ + "tool/translation_assistant/commit" : [ { "modifiers" : [], "key" : "Enter" } ], - "translation assistant insert original" : [ + "tool/translation_assistant/insert_original" : [ { "modifiers" : [], "key" : "Insert" } ], - "translation assistant next item" : [ + "tool/translation_assistant/next" : [ { "modifiers" : [], "key" : "PageDown" } ], - "translation assistant preview" : [ + "tool/translation_assistant/preview" : [ { "modifiers" : [], "key" : "F8" } ], - "video/play" : [ + "video/play/line" : [ { "modifiers" : [], "key" : "Home"