Convert the subs edit box buttons to commands

This makes they hotkeyable and extracts a large chunk of logic from the
giant mess that is SubsEditBox.
This commit is contained in:
Thomas Goyne 2012-10-08 19:07:54 -07:00
parent 44f0fcce07
commit 1b68790c4b
6 changed files with 369 additions and 284 deletions

View file

@ -49,10 +49,14 @@
#include "../ass_dialogue.h"
#include "../ass_file.h"
#include "../ass_karaoke.h"
#include "../ass_override.h"
#include "../ass_style.h"
#include "../dialog_colorpicker.h"
#include "../dialog_search_replace.h"
#include "../include/aegisub/context.h"
#include "../subs_edit_ctrl.h"
#include "../subs_grid.h"
#include "../text_selection_controller.h"
#include "../video_context.h"
namespace {
@ -74,16 +78,319 @@ struct validate_sel_multiple : public Command {
}
};
template<class T>
T get_value(AssDialogue const& line, int blockn, T initial, wxString const& tag, wxString alt = wxString()) {
for (int i = blockn; i >= 0; i--) {
AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(line.Blocks[i]);
if (!ovr) continue;
for (int j = (int)ovr->Tags.size() - 1; j >= 0; j--) {
if (ovr->Tags[j]->Name == tag || ovr->Tags[j]->Name == alt) {
return ovr->Tags[j]->Params[0]->Get<T>(initial);
}
}
}
return initial;
}
/// Get the block index in the text of the position
int block_at_pos(wxString const& text, int pos) {
int n = 0;
int max = text.size() - 1;
for (int i = 0; i <= pos && i <= max; ++i) {
if (i > 0 && text[i] == '{')
n++;
if (text[i] == '}' && i != max && i != pos && i != pos -1 && (i+1 == max || text[i+1] != '{'))
n++;
}
return n;
}
void set_tag(const agi::Context *c, wxString const& tag, wxString const& value, bool at_end = false) {
AssDialogue * const line = c->selectionController->GetActiveLine();
if (line->Blocks.empty())
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int start = at_end ? sel_end : sel_start;
int blockn = block_at_pos(line->Text, start);
AssDialogueBlockPlain *plain = 0;
AssDialogueBlockOverride *ovr = 0;
while (blockn >= 0) {
AssDialogueBlock *block = line->Blocks[blockn];
if (dynamic_cast<AssDialogueBlockDrawing*>(block))
--blockn;
else if ((plain = dynamic_cast<AssDialogueBlockPlain*>(block))) {
// Cursor is in a comment block, so try the previous block instead
if (plain->GetText().StartsWith("{")) {
--blockn;
start = line->Text.rfind('{', start);
}
else
break;
}
else {
ovr = dynamic_cast<AssDialogueBlockOverride*>(block);
assert(ovr);
break;
}
}
// If we didn't hit a suitable block for inserting the override just put
// it at the beginning of the line
if (blockn < 0)
start = 0;
wxString insert = tag + value;
int shift = insert.size();
if (plain || blockn < 0) {
line->Text = line->Text.Left(start) + "{" + insert + "}" + line->Text.Mid(start);
shift += 2;
line->ParseASSTags();
}
else if(ovr) {
wxString alt;
if (tag == "\\c") alt = "\\1c";
// Remove old of same
bool found = false;
for (size_t i = 0; i < ovr->Tags.size(); i++) {
wxString name = ovr->Tags[i]->Name;
if (tag == name || alt == name) {
shift -= ((wxString)*ovr->Tags[i]).size();
if (found) {
delete ovr->Tags[i];
ovr->Tags.erase(ovr->Tags.begin() + i);
i--;
}
else {
ovr->Tags[i]->Params[0]->Set(value);
ovr->Tags[i]->Params[0]->omitted = false;
found = true;
}
}
}
if (!found)
ovr->AddTag(insert);
line->UpdateText();
}
else
assert(false);
if (!at_end)
c->textSelectionController->SetSelection(sel_start + shift, sel_end + shift);
}
void set_text(AssDialogue *line, wxString const& value) {
line->Text = value;
}
void commit_text(agi::Context const * const c, wxString const& desc, int *commit_id = 0) {
SubtitleSelection const& sel = c->selectionController->GetSelectedSet();
for_each(sel.begin(), sel.end(),
bind(set_text, std::tr1::placeholders::_1, c->selectionController->GetActiveLine()->Text));
int new_commit_id = c->ass->Commit(desc, AssFile::COMMIT_DIAG_TEXT, commit_id ? *commit_id : -1, sel.size() == 1 ? *sel.begin() : 0);
if (commit_id)
*commit_id = new_commit_id;
}
void toggle_override_tag(const agi::Context *c, bool (AssStyle::*field), const char *tag, wxString const& undo_msg) {
AssDialogue *const line = c->selectionController->GetActiveLine();
AssStyle const* const style = c->ass->GetStyle(line->Style);
bool state = style ? style->*field : AssStyle().*field;
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int blockn = block_at_pos(line->Text, sel_start);
state = get_value(*line, blockn, state, tag);
set_tag(c, tag, state ? "0" : "1");
if (sel_start != sel_end)
set_tag(c, tag, state ? "1" : "0", true);
line->ClearBlocks();
commit_text(c, undo_msg);
}
void got_color(const agi::Context *c, const char *tag, int *commit_id, wxColour new_color) {
if (new_color.Ok()) {
set_tag(c, tag, AssColor(new_color).GetASSFormatted(false));
commit_text(c, _("set color"), commit_id);
}
}
void show_color_picker(const agi::Context *c, AssColor (AssStyle::*field), const char *tag, const char *alt) {
AssDialogue *const line = c->selectionController->GetActiveLine();
AssStyle const* const style = c->ass->GetStyle(line->Style);
wxColor color = (style ? style->*field : AssStyle().*field).GetWXColor();
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int blockn = block_at_pos(line->Text, sel_start);
color = get_value(*line, blockn, color, tag, alt);
int commit_id = -1;
const wxColor newColor = GetColorFromUser(c->parent, color, bind(got_color, c, tag, &commit_id, std::tr1::placeholders::_1));
line->ClearBlocks();
commit_text(c, _("set color"), &commit_id);
if (!newColor.IsOk()) {
c->ass->Undo();
c->textSelectionController->SetSelection(sel_start, sel_end);
}
}
struct edit_color_primary : public Command {
CMD_NAME("edit/color/primary")
STR_MENU("Primary Color...")
STR_DISP("Primary Color")
STR_HELP("Primary Color")
void operator()(agi::Context *c) {
show_color_picker(c, &AssStyle::primary, "\\c", "\\1c");
}
};
struct edit_color_secondary : public Command {
CMD_NAME("edit/color/secondary")
STR_MENU("Secondary Color...")
STR_DISP("Secondary Color")
STR_HELP("Secondary Color")
void operator()(agi::Context *c) {
show_color_picker(c, &AssStyle::secondary, "\\c", "\\1c");
}
};
struct edit_color_outline : public Command {
CMD_NAME("edit/color/outline")
STR_MENU("Outline Color...")
STR_DISP("Outline Color")
STR_HELP("Outline Color")
void operator()(agi::Context *c) {
show_color_picker(c, &AssStyle::outline, "\\c", "\\1c");
}
};
struct edit_color_shadow : public Command {
CMD_NAME("edit/color/shadow")
STR_MENU("Shadow Color...")
STR_DISP("Shadow Color")
STR_HELP("Shadow Color")
void operator()(agi::Context *c) {
show_color_picker(c, &AssStyle::shadow, "\\c", "\\1c");
}
};
struct edit_style_bold : public Command {
CMD_NAME("edit/style/bold")
STR_MENU("Bold")
STR_DISP("Bold")
STR_HELP("Bold")
void operator()(agi::Context *c) {
toggle_override_tag(c, &AssStyle::bold, "\\b", _("toggle bold"));
}
};
struct edit_style_italic : public Command {
CMD_NAME("edit/style/italic")
STR_MENU("Italics")
STR_DISP("Italics")
STR_HELP("Italics")
void operator()(agi::Context *c) {
toggle_override_tag(c, &AssStyle::italic, "\\i", _("toggle italic"));
}
};
struct edit_style_underline : public Command {
CMD_NAME("edit/style/underline")
STR_MENU("Underline")
STR_DISP("Underline")
STR_HELP("Underline")
void operator()(agi::Context *c) {
toggle_override_tag(c, &AssStyle::underline, "\\u", _("toggle underline"));
}
};
struct edit_style_strikeout : public Command {
CMD_NAME("edit/style/strikeout")
STR_MENU("Strikeout")
STR_DISP("Strikeout")
STR_HELP("Strikeout")
void operator()(agi::Context *c) {
toggle_override_tag(c, &AssStyle::strikeout, "\\s", _("toggle strikeout"));
}
};
struct edit_font : public Command {
CMD_NAME("edit/font")
STR_MENU("Font Face...")
STR_DISP("Font Face")
STR_HELP("Font Face")
void operator()(agi::Context *c) {
AssDialogue *const line = c->selectionController->GetActiveLine();
line->ParseASSTags();
const int blockn = block_at_pos(line->Text, c->textSelectionController->GetInsertionPoint());
const AssStyle *style = c->ass->GetStyle(line->Style);
const AssStyle default_style;
if (!style)
style = &default_style;
const wxFont startfont(
get_value(*line, blockn, (int)style->fontsize, "\\fs"),
wxFONTFAMILY_DEFAULT,
get_value(*line, blockn, style->italic, "\\i") ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL,
get_value(*line, blockn, style->bold, "\\b") ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL,
get_value(*line, blockn, style->underline, "\\u"),
get_value(*line, blockn, style->font, "\\fn"));
const wxFont font = wxGetFontFromUser(c->parent, startfont);
if (!font.Ok() || font == startfont) {
line->ClearBlocks();
return;
}
if (font.GetFaceName() != startfont.GetFaceName())
set_tag(c, "\\fn", font.GetFaceName());
if (font.GetPointSize() != startfont.GetPointSize())
set_tag(c, "\\fs", wxString::Format("%d", font.GetPointSize()));
if (font.GetWeight() != startfont.GetWeight())
set_tag(c, "\\b", wxString::Format("%d", font.GetWeight() == wxFONTWEIGHT_BOLD));
if (font.GetStyle() != startfont.GetStyle())
set_tag(c, "\\i", wxString::Format("%d", font.GetStyle() == wxFONTSTYLE_ITALIC));
if (font.GetUnderlined() != startfont.GetUnderlined())
set_tag(c, "\\i", wxString::Format("%d", font.GetUnderlined()));
line->ClearBlocks();
commit_text(c, _("set font"));
}
};
/// Find and replace words in subtitles.
struct edit_find_replace : public Command {
CMD_NAME("edit/find_replace")
STR_MENU("Find and R&eplace...")
STR_DISP("Find and Replace")
STR_HELP("Find and replace words in subtitles")
STR_MENU("Find and R&eplace...")
STR_DISP("Find and Replace")
STR_HELP("Find and replace words in subtitles")
void operator()(agi::Context *c) {
c->videoController->Stop();
Search.OpenDialog(true);
void operator()(agi::Context *c) {
c->videoController->Stop();
Search.OpenDialog(true);
}
};
@ -432,6 +739,11 @@ struct edit_undo : public Command {
namespace cmd {
void init_edit() {
reg(new edit_color_primary);
reg(new edit_color_secondary);
reg(new edit_color_outline);
reg(new edit_color_shadow);
reg(new edit_font);
reg(new edit_find_replace);
reg(new edit_line_copy);
reg(new edit_line_cut);
@ -445,6 +757,10 @@ namespace cmd {
reg(new edit_line_paste_over);
reg(new edit_line_recombine);
reg(new edit_line_split_by_karaoke);
reg(new edit_style_bold);
reg(new edit_style_italic);
reg(new edit_style_underline);
reg(new edit_style_strikeout);
reg(new edit_redo);
reg(new edit_undo);
}

View file

@ -99,14 +99,24 @@ INSERT_ICON("audio/play/selection/begin", button_playfirstfiveh)
INSERT_ICON("audio/play/selection/end", button_playlastfiveh)
INSERT_ICON("audio/play/to_end", button_playtoend)
INSERT_ICON("audio/stop", button_stop)
INSERT_ICON("edit/color/primary", button_color_one);
INSERT_ICON("edit/color/secondary", button_color_two);
INSERT_ICON("edit/color/outline", button_color_three);
INSERT_ICON("edit/color/shadow", button_color_four);
INSERT_ICON("edit/font", button_fontname);
INSERT_ICON("edit/line/copy", copy_button)
INSERT_ICON("edit/line/cut", cut_button)
INSERT_ICON("edit/line/delete", delete_button)
INSERT_ICON("edit/line/paste", paste_button)
INSERT_ICON("edit/line/swap", arrow_sort)
INSERT_ICON("edit/style/bold", button_bold)
INSERT_ICON("edit/style/italic", button_italics)
INSERT_ICON("edit/style/strikeout", button_strikeout)
INSERT_ICON("edit/style/underline", button_underline)
INSERT_ICON("edit/redo", redo_button)
INSERT_ICON("edit/search_replace", find_replace_menu)
INSERT_ICON("edit/undo", undo_button)
INSERT_ICON("grid/line/next/create", button_audio_commit)
INSERT_ICON("grid/tag/cycle_hiding", toggle_tag_hiding)
INSERT_ICON("help/bugs", bugtracker_button)
INSERT_ICON("help/contents", contents_button)

View file

@ -267,11 +267,10 @@ class DialogColorPicker : public wxDialog {
void OnMouse(wxMouseEvent &evt);
void OnCaptureLost(wxMouseCaptureLostEvent&);
ColorCallback callback;
void *callbackUserdata;
std::tr1::function<void (wxColour)> callback;
public:
DialogColorPicker(wxWindow *parent, wxColour initial_color, ColorCallback callback = NULL, void *userdata = NULL);
DialogColorPicker(wxWindow *parent, wxColour initial_color, std::tr1::function<void (wxColour)> callback);
~DialogColorPicker();
void SetColor(wxColour new_color);
@ -625,15 +624,15 @@ void ColorPickerScreenDropper::DropFromScreenXY(int x, int y)
Refresh(false);
}
wxColour GetColorFromUser(wxWindow *parent, wxColour original, ColorCallback callback, void* userdata)
wxColour GetColorFromUser(wxWindow* parent, wxColour original, std::tr1::function<void (wxColour)> callback)
{
DialogColorPicker dialog(parent, original, callback, userdata);
DialogColorPicker dialog(parent, original, callback);
if (dialog.ShowModal() == wxID_OK)
original = dialog.GetColor();
else
original = wxNullColour;
if (callback)
callback(userdata, original);
callback(original);
return original;
}
@ -650,10 +649,9 @@ static wxBitmap *make_rgb_image(int width, int offset) {
return new wxBitmap(img);
}
DialogColorPicker::DialogColorPicker(wxWindow *parent, wxColour initial_color, ColorCallback callback, void* userdata)
DialogColorPicker::DialogColorPicker(wxWindow *parent, wxColour initial_color, std::tr1::function<void (wxColour)> callback)
: wxDialog(parent, -1, _("Select Color"))
, callback(callback)
, callbackUserdata(userdata)
{
memset(rgb_spectrum, 0, sizeof rgb_spectrum);
hsl_spectrum = 0;
@ -1035,7 +1033,7 @@ void DialogColorPicker::UpdateSpectrumDisplay()
}
preview_box->SetBitmap(tempBmp);
if (callback) callback(callbackUserdata, cur_color);
callback(cur_color);
}
wxBitmap *DialogColorPicker::MakeGBSpectrum()

View file

@ -35,25 +35,17 @@
///
#ifndef AGI_PRE
#include <tr1/functional>
#include <wx/colour.h>
#endif
/// Callback function for GetColorFromUser
typedef void (*ColorCallback)(void* userdata, wxColor color);
/// Wrapper used by templated version of GetColorFromUser
template<class T, void (T::*method)(wxColor)>
void ColorCallbackWrapper(void* obj, wxColor color) {
(static_cast<T*>(obj)->*method)(color);
}
/// @brief Get a color from the user via a color picker dialog
/// @param parent Parent window
/// @param original Initial color to select
/// @param callback Function called whenever the selected color changes if not NULL
/// @param userdata Passed to callback function
/// @return Last selected color when dialog is closed, or wxNullColour if the dialog was cancelled
wxColor GetColorFromUser(wxWindow* parent, wxColor original, ColorCallback callback = NULL, void* userdata = NULL);
/// @param callback Function called whenever the selected color changes
/// @return Last selected color when dialog is closed, or wxNullColour if the dialog was canceled
wxColour GetColorFromUser(wxWindow* parent, wxColour original, std::tr1::function<void (wxColour)> callback);
/// @brief Get a color from the user via a color picker dialog
/// @param T Class which the callback method belongs to
@ -61,8 +53,8 @@ wxColor GetColorFromUser(wxWindow* parent, wxColor original, ColorCallback callb
/// @param parent Parent window
/// @param original Initial color to select
/// @param callbackObj Object to call callback method on. Must be of type T.
/// @return Last selected color when dialog is closed, or wxNullColour if the dialog was cancelled
template<class T, void (T::*method)(wxColor)>
wxColor GetColorFromUser(wxWindow* parent, wxColor original, T* callbackObj) {
return GetColorFromUser(parent, original, &ColorCallbackWrapper<T, method>, callbackObj);
/// @return Last selected color when dialog is closed, or wxNullColour if the dialog was canceled
template<class T, void (T::*method)(wxColour)>
wxColour GetColorFromUser(wxWindow* parent, wxColour original, T* callbackObj) {
return GetColorFromUser(parent, original, bind(method, callbackObj, std::tr1::placeholders::_1));
}

View file

@ -54,10 +54,7 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_override.h"
#include "ass_style.h"
#include "command/command.h"
#include "dialog_colorpicker.h"
#include "dialog_search_replace.h"
#include "include/aegisub/context.h"
#include "include/aegisub/hotkey.h"
@ -82,41 +79,6 @@ struct field_setter : public std::binary_function<AssDialogue*, T, void> {
}
};
/// @brief Get the value of a tag at a specified position in a line
/// @param line Line to get the value from
/// @param blockn Block number in the line
/// @param initial Value from style to use if the tag does not exist
/// @param tag Tag to get the value of
/// @param alt Alternate name of the tag, if any
template<class T>
static T get_value(AssDialogue const& line, int blockn, T initial, wxString tag, wxString alt = wxString()) {
for (int i = blockn; i >= 0; i--) {
AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(line.Blocks[i]);
if (!ovr) continue;
for (int j = (int)ovr->Tags.size() - 1; j >= 0; j--) {
if (ovr->Tags[j]->Name == tag || ovr->Tags[j]->Name == alt) {
return ovr->Tags[j]->Params[0]->Get<T>(initial);
}
}
}
return initial;
}
/// Get the block index in the text of the position
int block_at_pos(wxString const& text, int pos) {
int n = 0;
int max = text.size() - 1;
for (int i = 0; i <= pos && i <= max; ++i) {
if (i > 0 && text[i] == '{')
n++;
if (text[i] == '}' && i != max && i != pos && i != pos -1 && (i+1 == max || text[i+1] != '{'))
n++;
}
return n;
}
/// Work around wxGTK's fondness for generating events from ChangeValue
void change_value(wxTextCtrl *ctrl, wxString const& value) {
if (value != ctrl->GetValue())
@ -189,18 +151,18 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context)
// Middle-bottom controls
MiddleBotSizer = new wxBoxSizer(wxHORIZONTAL);
MakeButton(GETIMAGE(button_bold_16), _("Bold"), bind(&SubsEditBox::OnFlagButton, this, &AssStyle::bold, "\\b", _("toggle bold")));
MakeButton(GETIMAGE(button_italics_16), _("Italics"), bind(&SubsEditBox::OnFlagButton, this, &AssStyle::italic, "\\i", _("toggle italic")));
MakeButton(GETIMAGE(button_underline_16), _("Underline"), bind(&SubsEditBox::OnFlagButton, this, &AssStyle::underline, "\\u", _("toggle underline")));
MakeButton(GETIMAGE(button_strikeout_16), _("Strikeout"), bind(&SubsEditBox::OnFlagButton, this, &AssStyle::strikeout, "\\s", _("toggle strikeout")));
MakeButton(GETIMAGE(button_fontname_16), _("Font Face"), bind(&SubsEditBox::OnFontButton, this));
MakeButton("edit/style/bold");
MakeButton("edit/style/italic");
MakeButton("edit/style/underline");
MakeButton("edit/style/strikeout");
MakeButton("edit/font");
MiddleBotSizer->AddSpacer(5);
MakeButton(GETIMAGE(button_color_one_16), _("Primary color"), bind(&SubsEditBox::OnColorButton, this, &AssStyle::primary, "\\c", "\\1c"));
MakeButton(GETIMAGE(button_color_two_16), _("Secondary color"), bind(&SubsEditBox::OnColorButton, this, &AssStyle::secondary, "\\2c", ""));
MakeButton(GETIMAGE(button_color_three_16), _("Outline color"), bind(&SubsEditBox::OnColorButton, this, &AssStyle::outline, "\\3c", ""));
MakeButton(GETIMAGE(button_color_four_16), _("Shadow color"), bind(&SubsEditBox::OnColorButton, this, &AssStyle::shadow, "\\4c", ""));
MakeButton("edit/color/primary");
MakeButton("edit/color/secondary");
MakeButton("edit/color/outline");
MakeButton("edit/color/shadow");
MiddleBotSizer->AddSpacer(5);
MakeButton(GETIMAGE(button_audio_commit_16), _("Commits the text (Enter)"), bind(&cmd::call, "grid/line/next/create", c));
MakeButton("grid/line/next/create");
MiddleBotSizer->AddSpacer(10);
ByTime = MakeRadio(_("T&ime"), true, _("Time by h:mm:ss.cs"));
@ -227,7 +189,7 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context)
TextEdit->SetModEventMask(wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT | wxSTC_STARTACTION);
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnLayerEnter, this, Layer->GetId());
Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &SubsEditBox::OnLayerChange, this, Layer->GetId());
Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &SubsEditBox::OnLayerEnter, this, Layer->GetId());
Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &SubsEditBox::OnCommentChange, this, CommentBox->GetId());
Bind(wxEVT_SIZE, &SubsEditBox::OnSize, this);
@ -267,13 +229,13 @@ TimeEdit *SubsEditBox::MakeTimeCtrl(bool end, wxString const& tooltip, void (Sub
return ctrl;
}
template<class Handler>
void SubsEditBox::MakeButton(wxBitmap const& icon, wxString const& tooltip, Handler const& handler) {
wxBitmapButton *btn = new wxBitmapButton(this, -1, icon);
btn->SetToolTip(tooltip);
void SubsEditBox::MakeButton(const char *cmd_name) {
cmd::Command *command = cmd::get(cmd_name);
wxBitmapButton *btn = new wxBitmapButton(this, -1, command->Icon(16));
btn->SetToolTip(command->StrHelp());
MiddleBotSizer->Add(btn, wxSizerFlags().Center().Expand());
Bind(wxEVT_COMMAND_BUTTON_CLICKED, handler, btn->GetId());
btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, std::tr1::bind(cmd::call, cmd_name, c));
}
wxComboBox *SubsEditBox::MakeComboBox(wxString const& initial_text, int style, void (SubsEditBox::*handler)(wxCommandEvent&), wxString const& tooltip) {
@ -445,7 +407,7 @@ void SubsEditBox::SetSelectedRows(T AssDialogue::*field, T value, wxString desc,
SetSelectedRows(field_setter<T>(field), value, desc, type, amend);
}
void SubsEditBox::CommitText(wxString desc) {
void SubsEditBox::CommitText(wxString const& desc) {
SetSelectedRows(&AssDialogue::Text, TextEdit->GetText(), desc, AssFile::COMMIT_DIAG_TEXT, true);
}
@ -537,7 +499,6 @@ void SubsEditBox::SetControlsState(bool state) {
}
}
void SubsEditBox::OnStyleChange(wxCommandEvent &) {
SetSelectedRows(&AssDialogue::Style, StyleBox->GetValue(), _("style change"), AssFile::COMMIT_DIAG_META);
}
@ -548,10 +509,6 @@ void SubsEditBox::OnActorChange(wxCommandEvent &evt) {
PopulateActorList();
}
void SubsEditBox::OnLayerChange(wxSpinEvent &event) {
OnLayerEnter(event);
}
void SubsEditBox::OnLayerEnter(wxCommandEvent &) {
SetSelectedRows(&AssDialogue::Layer, Layer->GetValue(), _("layer change"), AssFile::COMMIT_DIAG_META);
}
@ -567,6 +524,7 @@ void SubsEditBox::OnEndTimeChange(wxCommandEvent &) {
void SubsEditBox::OnDurationChange(wxCommandEvent &) {
CommitTimes(TIME_DURATION);
}
void SubsEditBox::OnMarginLChange(wxCommandEvent &) {
SetSelectedRows(std::mem_fun(&AssDialogue::SetMarginString<0>), MarginL->GetValue(), _("MarginL change"), AssFile::COMMIT_DIAG_META);
if (line) change_value(MarginL, line->GetMarginString(0, false));
@ -594,171 +552,3 @@ void SubsEditBox::OnEffectChange(wxCommandEvent &) {
void SubsEditBox::OnCommentChange(wxCommandEvent &) {
SetSelectedRows(&AssDialogue::Comment, CommentBox->GetValue(), _("comment change"), AssFile::COMMIT_DIAG_META);
}
void SubsEditBox::SetTag(wxString tag, wxString value, bool atEnd) {
assert(line);
if (line->Blocks.empty())
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int start = atEnd ? sel_end : sel_start;
int blockn = block_at_pos(line->Text, start);
AssDialogueBlockPlain *plain = 0;
AssDialogueBlockOverride *ovr = 0;
while (blockn >= 0) {
AssDialogueBlock *block = line->Blocks[blockn];
if (dynamic_cast<AssDialogueBlockDrawing*>(block))
--blockn;
else if ((plain = dynamic_cast<AssDialogueBlockPlain*>(block))) {
// Cursor is in a comment block, so try the previous block instead
if (plain->GetText().StartsWith("{")) {
--blockn;
start = line->Text.rfind('{', start);
}
else
break;
}
else {
ovr = dynamic_cast<AssDialogueBlockOverride*>(block);
assert(ovr);
break;
}
}
// If we didn't hit a suitable block for inserting the override just put
// it at the beginning of the line
if (blockn < 0)
start = 0;
wxString insert = tag + value;
int shift = insert.size();
if (plain || blockn < 0) {
line->Text = line->Text.Left(start) + "{" + insert + "}" + line->Text.Mid(start);
shift += 2;
line->ParseASSTags();
}
else if(ovr) {
wxString alt;
if (tag == "\\c") alt = "\\1c";
// Remove old of same
bool found = false;
for (size_t i = 0; i < ovr->Tags.size(); i++) {
wxString name = ovr->Tags[i]->Name;
if (tag == name || alt == name) {
shift -= ((wxString)*ovr->Tags[i]).size();
if (found) {
delete ovr->Tags[i];
ovr->Tags.erase(ovr->Tags.begin() + i);
i--;
}
else {
ovr->Tags[i]->Params[0]->Set(value);
ovr->Tags[i]->Params[0]->omitted = false;
found = true;
}
}
}
if (!found) {
ovr->AddTag(insert);
}
line->UpdateText();
}
else
assert(false);
TextEdit->SetTextTo(line->Text);
if (!atEnd) c->textSelectionController->SetSelection(sel_start + shift, sel_end + shift);
TextEdit->SetFocus();
}
void SubsEditBox::OnFlagButton(bool (AssStyle::*field), const char *tag, wxString const& undo_msg) {
AssStyle *style = c->ass->GetStyle(line->Style);
bool state = style ? style->*field : AssStyle().*field;
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int blockn = block_at_pos(line->Text, sel_start);
state = get_value(*line, blockn, state, tag);
SetTag(tag, state ? "0" : "1");
if (sel_start != sel_end)
SetTag(tag, state ? "1" : "0", true);
line->ClearBlocks();
commitId = -1;
CommitText(undo_msg);
}
void SubsEditBox::OnFontButton() {
line->ParseASSTags();
int blockn = block_at_pos(line->Text, c->textSelectionController->GetInsertionPoint());
AssStyle *style = c->ass->GetStyle(line->Style);
AssStyle defStyle;
if (!style) style = &defStyle;
wxFont startfont(
get_value(*line, blockn, (int)style->fontsize, "\\fs"),
wxFONTFAMILY_DEFAULT,
get_value(*line, blockn, style->italic, "\\i") ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL,
get_value(*line, blockn, style->bold, "\\b") ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL,
get_value(*line, blockn, style->underline, "\\u"),
get_value(*line, blockn, style->font, "\\fn"));
wxFont font = wxGetFontFromUser(this, startfont);
if (!font.Ok() || font == startfont) {
line->ClearBlocks();
return;
}
if (font.GetFaceName() != startfont.GetFaceName())
SetTag("\\fn", font.GetFaceName());
if (font.GetPointSize() != startfont.GetPointSize())
SetTag("\\fs", wxString::Format("%d", font.GetPointSize()));
if (font.GetWeight() != startfont.GetWeight())
SetTag("\\b", wxString::Format("%d", font.GetWeight() == wxFONTWEIGHT_BOLD));
if (font.GetStyle() != startfont.GetStyle())
SetTag("\\i", wxString::Format("%d", font.GetStyle() == wxFONTSTYLE_ITALIC));
if (font.GetUnderlined() != startfont.GetUnderlined())
SetTag("\\i", wxString::Format("%d", font.GetUnderlined()));
line->ClearBlocks();
commitId = -1;
CommitText(_("set font"));
}
void SubsEditBox::OnColorButton(AssColor (AssStyle::*field), const char *tag, const char *alt) {
AssStyle *style = c->ass->GetStyle(line->Style);
wxColor color = (style ? style->*field : AssStyle().*field).GetWXColor();
colorTag = tag;
commitId = -1;
line->ParseASSTags();
int sel_start = c->textSelectionController->GetSelectionStart();
int sel_end = c->textSelectionController->GetSelectionEnd();
int blockn = block_at_pos(line->Text, sel_start);
color = get_value(*line, blockn, color, colorTag, alt);
wxColor newColor = GetColorFromUser<SubsEditBox, &SubsEditBox::SetColorCallback>(c->parent, color, this);
line->ClearBlocks();
CommitText(_("set color"));
if (!newColor.IsOk()) {
c->ass->Undo();
c->textSelectionController->SetSelection(sel_start, sel_end);
}
}
void SubsEditBox::SetColorCallback(wxColor newColor) {
if (newColor.Ok()) {
SetTag(colorTag, AssColor(newColor).GetASSFormatted(false));
CommitText(_("set color"));
}
}

View file

@ -50,9 +50,7 @@
namespace agi { namespace vfr { class Framerate; } }
namespace agi { struct Context; }
struct AssColor;
class AssDialogue;
class AssStyle;
class AssTime;
class SubsTextEditCtrl;
class TextSelectionController;
@ -123,7 +121,7 @@ class SubsEditBox : public wxPanel {
void CommitTimes(TimeField field);
/// @brief Commits the current edit box contents
/// @param desc Undo description to use
void CommitText(wxString desc);
void CommitText(wxString const& desc);
/// Last commit ID for undo coalescing
int commitId;
@ -145,8 +143,7 @@ class SubsEditBox : public wxPanel {
// Constructor helpers
wxTextCtrl *MakeMarginCtrl(wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&));
TimeEdit *MakeTimeCtrl(bool end, wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&));
template<class Handler>
void MakeButton(wxBitmap const& icon, wxString const& tooltip, Handler const& handler);
void MakeButton(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);
@ -160,7 +157,6 @@ class SubsEditBox : public wxPanel {
void OnStyleChange(wxCommandEvent &event);
void OnActorChange(wxCommandEvent &event);
void OnLayerEnter(wxCommandEvent &event);
void OnLayerChange(wxSpinEvent &event);
void OnStartTimeChange(wxCommandEvent &);
void OnEndTimeChange(wxCommandEvent &);
void OnDurationChange(wxCommandEvent &);
@ -172,25 +168,8 @@ class SubsEditBox : public wxPanel {
void OnSize(wxSizeEvent &event);
void OnUndoTimer(wxTimerEvent&);
void OnFlagButton(bool (AssStyle::*field), const char *tag, wxString const& undo_msg);
void OnColorButton(AssColor (AssStyle::*field), const char *tag, const char *alt);
void OnFontButton();
void SetPlaceholderCtrl(wxControl *ctrl, wxString const& value);
/// @brief Set the value of a tag for the currently selected text
/// @param tag Tag to set
/// @param value New value of tag
/// @param atEnd Set the value at the end of the selection rather than beginning
void SetTag(wxString tag, wxString value, bool atEnd = false);
/// @brief Callback function for the color picker
/// @param newColor New color selected in the picker
void SetColorCallback(wxColor newColor);
/// Which color is currently being set
wxString colorTag;
/// @brief Set a field in each selected line to a specified value
/// @param set Callable which does the setting
/// @param value Value to pass to set