From 0e04794ffdadd8bb8dc8c4a651059486f29deef9 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Mon, 14 Apr 2014 12:05:19 -0700 Subject: [PATCH] Make the edit box buttons less dumb with multiple lines selected Apply the modification at the cursor position to each selected line rather than just setting all selected lines to the active line's text. Still doesn't have good results in any nontrivial cases, but it's at least sometimes useful. --- src/command/edit.cpp | 192 ++++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 74 deletions(-) diff --git a/src/command/edit.cpp b/src/command/edit.cpp index 51a6e6be0..e2a2dd02b 100644 --- a/src/command/edit.cpp +++ b/src/command/edit.cpp @@ -199,9 +199,6 @@ int block_at_pos(std::string const& text, int pos) { } void set_tag(AssDialogue *line, std::vector> &blocks, std::string const& tag, std::string const& value, int &sel_start, int &sel_end, bool at_end = false) { - if (blocks.empty()) - blocks = line->ParseTags(); - int start = at_end ? sel_end : sel_start; int blockn = block_at_pos(line->Text, start); @@ -270,61 +267,106 @@ void set_tag(AssDialogue *line, std::vector> & } } -void commit_text(agi::Context const * const c, wxString const& desc, int sel_start = -1, int sel_end = -1, int *commit_id = nullptr) { - auto const& sel = c->selectionController->GetSelectedSet(); - std::string text = c->selectionController->GetActiveLine()->Text; - for_each(sel.begin(), sel.end(), [&](AssDialogue *d) { d->Text = text; }); +template +void update_lines(const agi::Context *c, wxString const& undo_msg, Func&& f) { + const int initial_sel_start = c->textSelectionController->GetSelectionStart(); + const int initial_sel_end = c->textSelectionController->GetSelectionEnd(); + const auto active_line = c->selectionController->GetActiveLine(); + int active_sel_start = initial_sel_start, active_sel_end = initial_sel_end; - int new_commit_id = c->ass->Commit(desc, AssFile::COMMIT_DIAG_TEXT, commit_id ? *commit_id : -1, sel.size() == 1 ? *sel.begin() : nullptr); - if (commit_id) - *commit_id = new_commit_id; - if (sel_start >= 0 && sel_end >= 0) - c->textSelectionController->SetSelection(sel_start, sel_end); + for (const auto line : c->selectionController->GetSelectedSet()) { + int sel_start = initial_sel_start; + int sel_end = initial_sel_end; + f(line, sel_start, sel_end); + if (line == active_line) { + active_sel_start = sel_start; + active_sel_end = sel_end; + } + } + + auto const& sel = c->selectionController->GetSelectedSet(); + c->ass->Commit(undo_msg, AssFile::COMMIT_DIAG_TEXT, -1, sel.size() == 1 ? *sel.begin() : nullptr); + if (active_sel_start >= 0 && active_sel_end >= 0) + c->textSelectionController->SetSelection(active_sel_start, active_sel_end); } 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; + update_lines(c, undo_msg, [&](AssDialogue *line, int &sel_start, int &sel_end) { + AssStyle const* const style = c->ass->GetStyle(line->Style); + bool state = style ? style->*field : AssStyle().*field; - auto blocks = line->ParseTags(); - int sel_start = c->textSelectionController->GetSelectionStart(); - int sel_end = c->textSelectionController->GetSelectionEnd(); - int blockn = block_at_pos(line->Text, sel_start); + auto blocks = line->ParseTags(); + int blockn = block_at_pos(line->Text, sel_start); - state = get_value(blocks, blockn, state, tag); + state = get_value(blocks, blockn, state, tag); - set_tag(line, blocks, tag, state ? "0" : "1", sel_start, sel_end); - if (sel_start != sel_end) - set_tag(line, blocks, tag, state ? "1" : "0", sel_start, sel_end, true); - - commit_text(c, undo_msg, sel_start, sel_end); + set_tag(line, blocks, tag, state ? "0" : "1", sel_start, sel_end); + if (sel_start != sel_end) + set_tag(line, blocks, tag, state ? "1" : "0", sel_start, sel_end, true); + }); } void show_color_picker(const agi::Context *c, agi::Color (AssStyle::*field), const char *tag, const char *alt, const char *alpha) { - AssDialogue *const line = c->selectionController->GetActiveLine(); - AssStyle const* const style = c->ass->GetStyle(line->Style); - agi::Color color = (style ? style->*field : AssStyle().*field); + agi::Color initial_color; + const int initial_sel_start = c->textSelectionController->GetSelectionStart(); + const int initial_sel_end = c->textSelectionController->GetSelectionEnd(); + const auto active_line = c->selectionController->GetActiveLine(); + int active_sel_start = initial_sel_start, active_sel_end = initial_sel_end; - auto blocks = line->ParseTags(); - int sel_start = c->textSelectionController->GetSelectionStart(); - int sel_end = c->textSelectionController->GetSelectionEnd(); - int blockn = block_at_pos(line->Text, sel_start); - int initial_sel_start = sel_start, initial_sel_end = sel_end; + struct line_info { + AssDialogue *line; + agi::Color color; + std::vector> blocks; + +#ifdef _MSC_VER + line_info(AssDialogue *line, agi::Color color, std::vector> blocks) + : line(line), color(color), blocks(std::move(blocks)) { } + line_info(line_info &&r) : line(r.line), color(r.color), blocks(std::move(r.blocks)) { } +#endif + }; + + auto const& sel = c->selectionController->GetSelectedSet(); + std::vector lines; + for (auto line : sel) { + AssStyle const* const style = c->ass->GetStyle(line->Style); + agi::Color color = (style ? style->*field : AssStyle().*field); + + auto blocks = line->ParseTags(); + int blockn = block_at_pos(line->Text, initial_sel_start); + + int a = get_value(blocks, blockn, (int)color.a, alpha, "\\alpha"); + color = get_value(blocks, blockn, color, tag, alt); + color.a = a; + + if (line == active_line) + initial_color = color; + + lines.push_back(line_info{line, color, std::move(blocks)}); + } - int a = get_value(blocks, blockn, (int)color.a, alpha, "\\alpha"); - color = get_value(blocks, blockn, color, tag, alt); - color.a = a; int commit_id = -1; - bool ok = GetColorFromUser(c->parent, color, true, [&](agi::Color new_color) { - set_tag(line, blocks, tag, new_color.GetAssOverrideFormatted(), sel_start, sel_end); - if (new_color.a != color.a) { - set_tag(line, blocks, alpha, str(boost::format("&H%02X&") % (int)new_color.a), sel_start, sel_end); - color.a = new_color.a; + bool ok = GetColorFromUser(c->parent, initial_color, true, [&](agi::Color new_color) { + for (auto& line : lines) { + int sel_start = initial_sel_start; + int sel_end = initial_sel_end; + + set_tag(line.line, line.blocks, tag, new_color.GetAssOverrideFormatted(), sel_start, sel_end); + if (new_color.a != line.color.a) { + set_tag(line.line, line.blocks, alpha, str(boost::format("&H%02X&") % (int)new_color.a), sel_start, sel_end); + line.color.a = new_color.a; + } + + if (line.line == active_line) { + active_sel_start = sel_start; + active_sel_end = sel_end; + } } - commit_text(c, _("set color"), sel_start, sel_end, &commit_id); + + commit_id = c->ass->Commit(_("set color"), AssFile::COMMIT_DIAG_TEXT, commit_id, sel.size() == 1 ? *sel.begin() : nullptr); + if (active_sel_start >= 0 && active_sel_end >= 0) + c->textSelectionController->SetSelection(active_sel_start, active_sel_end); }); - commit_text(c, _("set color"), -1, -1, &commit_id); + c->ass->Commit(_("set color"), AssFile::COMMIT_DIAG_TEXT, commit_id, sel.size() == 1 ? *sel.begin() : nullptr); if (!ok) { c->subsController->Undo(); @@ -436,41 +478,43 @@ struct edit_font final : public Command { STR_HELP("Select a font face and size") void operator()(agi::Context *c) override { - AssDialogue *const line = c->selectionController->GetActiveLine(); - auto blocks = line->ParseTags(); - const int blockn = block_at_pos(line->Text, c->textSelectionController->GetInsertionPoint()); + const int insertion_point = c->textSelectionController->GetInsertionPoint(); + std::vector> blocks; + auto font_for_line = [&](AssDialogue *const line) -> wxFont { + blocks = line->ParseTags(); + const int blockn = block_at_pos(line->Text, insertion_point); - const AssStyle *style = c->ass->GetStyle(line->Style); - const AssStyle default_style; - if (!style) - style = &default_style; + const AssStyle *style = c->ass->GetStyle(line->Style); + const AssStyle default_style; + if (!style) + style = &default_style; - int sel_start = c->textSelectionController->GetSelectionStart(); - int sel_end = c->textSelectionController->GetSelectionEnd(); + return wxFont( + get_value(blocks, blockn, (int)style->fontsize, "\\fs"), + wxFONTFAMILY_DEFAULT, + get_value(blocks, blockn, style->italic, "\\i") ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL, + get_value(blocks, blockn, style->bold, "\\b") ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL, + get_value(blocks, blockn, style->underline, "\\u"), + to_wx(get_value(blocks, blockn, style->font, "\\fn"))); + }; - const wxFont startfont( - get_value(blocks, blockn, (int)style->fontsize, "\\fs"), - wxFONTFAMILY_DEFAULT, - get_value(blocks, blockn, style->italic, "\\i") ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL, - get_value(blocks, blockn, style->bold, "\\b") ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL, - get_value(blocks, blockn, style->underline, "\\u"), - to_wx(get_value(blocks, blockn, style->font, "\\fn"))); + const wxFont initial = font_for_line(c->selectionController->GetActiveLine()); + const wxFont font = wxGetFontFromUser(c->parent, initial); + if (!font.Ok() || font == initial) return; - const wxFont font = wxGetFontFromUser(c->parent, startfont); - if (!font.Ok() || font == startfont) return; - - if (font.GetFaceName() != startfont.GetFaceName()) - set_tag(line, blocks, "\\fn", from_wx(font.GetFaceName()), sel_start, sel_end); - if (font.GetPointSize() != startfont.GetPointSize()) - set_tag(line, blocks, "\\fs", std::to_string(font.GetPointSize()), sel_start, sel_end); - if (font.GetWeight() != startfont.GetWeight()) - set_tag(line, blocks, "\\b", std::to_string(font.GetWeight() == wxFONTWEIGHT_BOLD), sel_start, sel_end); - if (font.GetStyle() != startfont.GetStyle()) - set_tag(line, blocks, "\\i", std::to_string(font.GetStyle() == wxFONTSTYLE_ITALIC), sel_start, sel_end); - if (font.GetUnderlined() != startfont.GetUnderlined()) - set_tag(line, blocks, "\\i", std::to_string(font.GetUnderlined()), sel_start, sel_end); - - commit_text(c, _("set font"), sel_start, sel_end); + update_lines(c, _("set font"), [&](AssDialogue *line, int &sel_start, int &sel_end) { + const wxFont startfont = font_for_line(line); + if (font.GetFaceName() != startfont.GetFaceName()) + set_tag(line, blocks, "\\fn", from_wx(font.GetFaceName()), sel_start, sel_end); + if (font.GetPointSize() != startfont.GetPointSize()) + set_tag(line, blocks, "\\fs", std::to_string(font.GetPointSize()), sel_start, sel_end); + if (font.GetWeight() != startfont.GetWeight()) + set_tag(line, blocks, "\\b", std::to_string(font.GetWeight() == wxFONTWEIGHT_BOLD), sel_start, sel_end); + if (font.GetStyle() != startfont.GetStyle()) + set_tag(line, blocks, "\\i", std::to_string(font.GetStyle() == wxFONTSTYLE_ITALIC), sel_start, sel_end); + if (font.GetUnderlined() != startfont.GetUnderlined()) + set_tag(line, blocks, "\\i", std::to_string(font.GetUnderlined()), sel_start, sel_end); + }); } };