Aegisub/aegisub/src/dialog_translation.cpp
Thomas Goyne 123f02f0fb Process hotkeys in wxEVT_CHAR_HOOK rather than wxEVT_KEY_DOWN
Char hook events propagate by default, removing the need for the event
filter to make key down events propagate, which was causing some funny
issues.

On Windows, the char hook handler runs before menu accelerators, fixing
a bug where Default context hotkeys would override more specific ones
when they appeared on a menu. Unfortunately, this is not the case on
GTK, so the dumb accelerator-disabling hack is still required.

Originally committed to SVN as r6724.
2012-04-27 19:07:49 +00:00

317 lines
11 KiB
C++

// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file dialog_translation.cpp
/// @brief Translation Assistant dialogue box and logic
/// @ingroup tools_ui
///
#include "config.h"
#include "dialog_translation.h"
#include "include/aegisub/context.h"
#include "include/aegisub/hotkey.h"
#include "ass_dialogue.h"
#include "ass_file.h"
#include "audio_controller.h"
#include "command/command.h"
#include "compat.h"
#include "help_button.h"
#include "libresrc/libresrc.h"
#include "persist_location.h"
#include "subs_edit_ctrl.h"
#include "selection_controller.h"
#include "utils.h"
#include "video_context.h"
#ifndef AGI_PRE
#include <wx/checkbox.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/settings.h>
#include <wx/stattext.h>
#endif
static void add_hotkey(wxSizer *sizer, wxWindow *parent, const char *command, wxString const& text) {
sizer->Add(new wxStaticText(parent, -1, text));
sizer->Add(new wxStaticText(parent, -1, hotkey::get_hotkey_str_first("Translation Assistant", command)));
}
// 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;
}
DialogTranslation::DialogTranslation(agi::Context *c)
: wxDialog(c->parent, -1, _("Translation Assistant"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX)
, c(c)
, file_change_connection(c->ass->AddCommitListener(&DialogTranslation::OnExternalCommit, this))
, active_line(c->selectionController->GetActiveLine())
, cur_block(0)
, line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>()))
, line_number(count_if(c->ass->Line.begin(), find(c->ass->Line.begin(), c->ass->Line.end(), active_line), cast<AssDialogue*>()) + 1)
, switching_lines(false)
{
SetIcon(GETICON(translation_toolbutton_16));
wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
wxSizer *translation_sizer = new wxBoxSizer(wxVERTICAL);
{
wxSizer *original_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Original"));
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);
}
{
translated_text = new SubsTextEditCtrl(this, wxSize(320, 80), 0, 0);
translated_text->SetWrapMode(wxSTC_WRAP_WORD);
translated_text->SetMarginWidth(1, 0);
translated_text->SetFocus();
translated_text->Bind(wxEVT_CHAR_HOOK, &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);
}
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"));
add_hotkey(hotkey_grid, this, "edit/line/delete", _("Delete line"));
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);
}
{
wxStaticBoxSizer *actions_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Actions"));
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);
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);
}
SetSizerAndFit(main_sizer);
persist.reset(new PersistLocation(this, "Tool/Translation Assistant"));
Bind(wxEVT_KEY_DOWN, &DialogTranslation::OnKeyDown, this);
active_line->ParseASSTags();
if (bad_block(active_line->Blocks[0])) {
if (!NextBlock())
throw NothingToTranslate(STD_STR(_("There is nothing to translate in the file.")));
}
else
UpdateDisplay();
c->selectionController->AddSelectionListener(this);
}
DialogTranslation::~DialogTranslation() {
c->selectionController->RemoveSelectionListener(this);
}
void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
if (switching_lines) return;
active_line = new_line;
active_line->ParseASSTags();
cur_block = 0;
line_number = count_if(c->ass->Line.begin(), find(c->ass->Line.begin(), c->ass->Line.end(), active_line), cast<AssDialogue*>()) + 1;
if (bad_block(active_line->Blocks[cur_block]) && !NextBlock()) {
wxMessageBox(_("No more lines to translate."));
EndModal(1);
}
}
void DialogTranslation::OnExternalCommit(int commit_type) {
if (commit_type == AssFile::COMMIT_NEW || commit_type & AssFile::COMMIT_DIAG_ADDREM) {
line_count = count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>());
line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), (int)line_number, (int)line_count));
}
if (commit_type & AssFile::COMMIT_DIAG_TEXT)
OnActiveLineChanged(active_line);
}
bool DialogTranslation::NextBlock() {
switching_lines = true;
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
++cur_block;
} while (bad_block(active_line->Blocks[cur_block]));
switching_lines = false;
UpdateDisplay();
return true;
}
bool DialogTranslation::PrevBlock() {
switching_lines = true;
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]));
switching_lines = false;
UpdateDisplay();
return true;
}
void DialogTranslation::UpdateDisplay() {
line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), (int)line_number, (int)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->GetText());
if (i == cur_block) {
original_text->StartUnicodeStyling(cur_size);
original_text->SetUnicodeStyling(cur_size, block->GetText().size(), 1);
}
}
else if (block->GetType() == BLOCK_OVERRIDE)
original_text->AppendText("{" + block->GetText() + "}");
}
original_text->SetReadOnly(true);
if (seek_video->IsChecked()) c->videoController->JumpToTime(active_line->Start);
translated_text->ClearAll();
translated_text->SetFocus();
}
void DialogTranslation::Commit(bool next) {
wxString new_value = translated_text->GetValue();
new_value.Replace("\r\n", "\\N");
new_value.Replace("\r", "\\N");
new_value.Replace("\n", "\\N");
*active_line->Blocks[cur_block] = AssDialogueBlockPlain(new_value);
active_line->UpdateText();
file_change_connection.Block();
c->ass->Commit(_("translation assistant"), AssFile::COMMIT_DIAG_TEXT);
file_change_connection.Unblock();
if (next) {
if (!NextBlock()) {
wxMessageBox(_("No more lines to translate."));
EndModal(1);
}
}
else {
UpdateDisplay();
}
}
void DialogTranslation::InsertOriginal() {
translated_text->AddText(active_line->Blocks[cur_block]->GetText());
}
void DialogTranslation::OnKeyDown(wxKeyEvent &evt) {
hotkey::check("Translation Assistant", c, evt);
}
void DialogTranslation::OnPlayVideoButton(wxCommandEvent &) {
c->videoController->PlayLine();
translated_text->SetFocus();
}
void DialogTranslation::OnPlayAudioButton(wxCommandEvent &) {
cmd::call("audio/play/selection", c);
translated_text->SetFocus();
}