From 78227a30da764d7ceee86c2818d493af95120eed Mon Sep 17 00:00:00 2001 From: Brendan Hagan Date: Tue, 26 Jul 2022 22:11:09 -0400 Subject: [PATCH 1/4] feat: add internal support for underlined text (closes #29) --- src/data/font.cpp | 5 ++++- src/data/font.hpp | 2 +- src/render/text/element.cpp | 9 ++++++--- src/util/tagged_string.cpp | 6 +++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/data/font.cpp b/src/data/font.cpp index d5c34b7c..db81e41b 100644 --- a/src/data/font.cpp +++ b/src/data/font.cpp @@ -50,7 +50,7 @@ void Font::initDependencies(Context& ctx, const Dependency& dep) const { shadow_color.initDependencies(ctx, dep); } -FontP Font::make(int add_flags, String const* other_family, Color const* other_color, double const* other_size) const { +FontP Font::make(int add_flags, bool add_underline, String const* other_family, Color const* other_color, double const* other_size) const { FontP f(new Font(*this)); f->flags |= add_flags; if (add_flags & FONT_CODE_STRING) { @@ -66,6 +66,9 @@ FontP Font::make(int add_flags, String const* other_family, Color const* other_c if (add_flags & FONT_SOFT) { f->color = f->separator_color; f->shadow_displacement = RealSize(0,0); // no shadow + } + if (add_underline) { + f->underline = true; } if (other_color) { f->color = *other_color; diff --git a/src/data/font.hpp b/src/data/font.hpp index 13a055a4..cc030f92 100644 --- a/src/data/font.hpp +++ b/src/data/font.hpp @@ -60,7 +60,7 @@ public: } /// Add style to a font, and optionally change the font family, color and size - FontP make(int add_flags, String const* other_family, Color const* other_color, double const* other_size) const; + FontP make(int add_flags, bool add_underline, String const* other_family, Color const* other_color, double const* other_size) const; /// Convert this font to a wxFont wxFont toWxFont(double scale) const; diff --git a/src/render/text/element.cpp b/src/render/text/element.cpp index 8cde8d88..fcc09fd9 100644 --- a/src/render/text/element.cpp +++ b/src/render/text/element.cpp @@ -34,7 +34,7 @@ struct Margins { // Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls struct TextElementsFromString { // What formatting is enabled? - int bold = 0, italic = 0, symbol = 0; + int bold = 0, italic = 0, underline = 0, symbol = 0; int soft = 0, kwpph = 0, param = 0, line = 0, soft_line = 0; int code = 0, code_kw = 0, code_string = 0, param_ref = 0; int param_id = 0, li = 0; @@ -78,7 +78,9 @@ private: if (is_tag(text, tag_start, _( " 0 ? FONT_SOFT : FONT_NORMAL) | (code > 0 ? FONT_CODE : FONT_NORMAL) | (code_kw > 0 ? FONT_CODE_KW : FONT_NORMAL) | - (code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL), + (code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL), + underline > 0, fonts.empty() ? nullptr : &fonts.back(), param > 0 || param_ref > 0 ? ¶m_colors[(param_id++) % param_colors_count] diff --git a/src/util/tagged_string.cpp b/src/util/tagged_string.cpp index 0da2669f..9ad82a81 100644 --- a/src/util/tagged_string.cpp +++ b/src/util/tagged_string.cpp @@ -645,7 +645,7 @@ String simplify_tagged(const String& str) { // (where is the negation of tag) bool add_or_cancel_tag(const String& tag, String& stack, bool all = false) { if (all || starts_with(tag, _("/")) || - starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym"))) { + starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym")) || starts_with(tag, _("u"))) { // cancel out all close tags, but not all open tags, // so is always removed // but is not @@ -692,8 +692,8 @@ String simplify_tagged_overlap(const String& str) { Char c = str.GetChar(i); if (c == _('<')) { String tag = tag_at(str, i); - if (starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym")) || - starts_with(tag, _("/b")) || starts_with(tag, _("/i")) || starts_with(tag, _("/sym"))) { + if (starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym")) || starts_with(tag, _("u")) || + starts_with(tag, _("/b")) || starts_with(tag, _("/i")) || starts_with(tag, _("/sym")) || starts_with(tag, _("/u"))) { // optimize this tag if (open_tags.find(_("<") + tag + _(">")) == String::npos) { // we are not already inside this tag From 132d8d9351cb408ab1296b28ed9c53069c6bdc04 Mon Sep 17 00:00:00 2001 From: Brendan Hagan Date: Tue, 26 Jul 2022 22:37:57 -0400 Subject: [PATCH 2/4] feat: add underline to panels and export --- data/en.mse-locale/locale | 7 +++++-- resource/tool/underline.png | Bin 0 -> 273 bytes resource/win32_res.rc | 1 + src/gui/set/cards_panel.cpp | 13 ++++++++----- src/gui/set/set_info_panel.cpp | 13 ++++++++----- src/gui/value/text.cpp | 10 ++++++++-- src/script/functions/export.cpp | 19 +++++++++++++++---- src/util/window_id.hpp | 3 ++- 8 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 resource/tool/underline.png diff --git a/data/en.mse-locale/locale b/data/en.mse-locale/locale index 66a4a552..54de6efc 100644 --- a/data/en.mse-locale/locale +++ b/data/en.mse-locale/locale @@ -67,7 +67,8 @@ menu: format: F&ormat bold: &Bold Ctrl+B - italic: &Italic Ctrl+I + italic: &Italic Ctrl+I + underline: &Underline Ctrl+U symbols: &Symbols Ctrl+M reminder text: &Reminder Text Ctrl+R insert symbol: I&nsert Symbol @@ -187,7 +188,8 @@ help: #format: bold: Makes the selected text bold - italic: Makes the selected text italic + italic: Makes the selected text italic + underline: Makes the selected text underlined symbols: Draws the selected text with symbols reminder text: Show reminder text for the selected keyword # spelling @@ -390,6 +392,7 @@ tooltip: bold: Bold italic: Italic + underline: Underline symbols: Symbols reminder text: Reminder Text diff --git a/resource/tool/underline.png b/resource/tool/underline.png new file mode 100644 index 0000000000000000000000000000000000000000..90d0df2868871c6cf1bab25affe0d9f8b3f98eac GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$x?CIhdqH#X?$N2_%BY~9*Y!?2h z{rUe=9fy8l?U(-(m`sFEeV_iPeWNmK)A{6xz&-Zw?GGia|0}^&^gUfcv*1X`gnjmc zo{g-_np*x&^x*npDC+Wt-z8{4+sXs`@BiMP%+Rv-k;3)Ae_+S0!x%EHv-|4^N|MkDje{TP~{@MQ}vm3aX7|tvG V&AV6mZa&bt44$rjF6*2UngI1lb~69~ literal 0 HcmV?d00001 diff --git a/resource/win32_res.rc b/resource/win32_res.rc index 6b5d2d66..bbdf8f37 100644 --- a/resource/win32_res.rc +++ b/resource/win32_res.rc @@ -39,6 +39,7 @@ tool/find IMAGE "tool/find.png" tool/bold IMAGE "tool/bold.png" tool/italic IMAGE "tool/italic.png" +tool/underline IMAGE "tool/underline.png" tool/symbol IMAGE "tool/symbol.png" tool/reminder IMAGE "tool/reminder.png" tool/no_auto IMAGE "tool/no_auto.png" diff --git a/src/gui/set/cards_panel.cpp b/src/gui/set/cards_panel.cpp index a70e222b..f9fa804d 100644 --- a/src/gui/set/cards_panel.cpp +++ b/src/gui/set/cards_panel.cpp @@ -88,7 +88,8 @@ CardsPanel::CardsPanel(Window* parent, int id) menuFormat = new wxMenu(); add_menu_item_tr(menuFormat, ID_FORMAT_BOLD, "bold", "bold", wxITEM_CHECK); - add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK); + add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK); + add_menu_item_tr(menuFormat, ID_FORMAT_UNDERLINE, "underline", "underline", wxITEM_CHECK); add_menu_item_tr(menuFormat, ID_FORMAT_SYMBOL, "symbol", "symbols", wxITEM_CHECK); add_menu_item_tr(menuFormat, ID_FORMAT_REMINDER, "reminder", "reminder_text", wxITEM_CHECK); menuFormat->AppendSeparator(); @@ -184,7 +185,8 @@ wxMenu* CardsPanel::makeAddCardsSubmenu(bool add_single_card_option) { void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { // Toolbar add_tool_tr(tb, ID_FORMAT_BOLD, "bold", "bold", false, wxITEM_CHECK); - add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK); + add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK); + add_tool_tr(tb, ID_FORMAT_UNDERLINE, "underline", "underline", false, wxITEM_CHECK); add_tool_tr(tb, ID_FORMAT_SYMBOL, "symbol", "symbols", false, wxITEM_CHECK); add_tool_tr(tb, ID_FORMAT_REMINDER, "reminder", "reminder_text", false, wxITEM_CHECK); tb->AddSeparator(); @@ -214,7 +216,8 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { // Toolbar tb->DeleteTool(ID_FORMAT_BOLD); - tb->DeleteTool(ID_FORMAT_ITALIC); + tb->DeleteTool(ID_FORMAT_ITALIC); + tb->DeleteTool(ID_FORMAT_UNDERLINE); tb->DeleteTool(ID_FORMAT_SYMBOL); tb->DeleteTool(ID_FORMAT_REMINDER); tb->DeleteTool(ID_CARD_ADD); @@ -253,7 +256,7 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) { break; } case ID_CARD_REMOVE: ev.Enable(card_list->canDelete()); break; - case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { + case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { if (focused_control(this) == ID_EDITOR) { ev.Enable(editor->canFormat(ev.GetId())); ev.Check (editor->hasFormat(ev.GetId())); @@ -327,7 +330,7 @@ void CardsPanel::onCommand(int id) { case ID_SELECT_COLUMNS: { card_list->selectColumns(); } - case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { + case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { if (focused_control(this) == ID_EDITOR) { editor->doFormat(id); } diff --git a/src/gui/set/set_info_panel.cpp b/src/gui/set/set_info_panel.cpp index d421e0f3..4e65fd37 100644 --- a/src/gui/set/set_info_panel.cpp +++ b/src/gui/set/set_info_panel.cpp @@ -35,14 +35,16 @@ void SetInfoPanel::onChangeSet() { void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { // Toolbar add_tool_tr(tb, ID_FORMAT_BOLD, "bold", "bold", false, wxITEM_CHECK); - add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK); + add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK); + add_tool_tr(tb, ID_FORMAT_UNDERLINE, "underline", "underline", false, wxITEM_CHECK); add_tool_tr(tb, ID_FORMAT_SYMBOL, "symbol", "symbols", false, wxITEM_CHECK); add_tool_tr(tb, ID_FORMAT_REMINDER, "reminder", "reminder_text", false, wxITEM_CHECK); tb->Realize(); // Menus auto menuFormat = new wxMenu(); add_menu_item_tr(menuFormat, ID_FORMAT_BOLD, "bold", "bold", wxITEM_CHECK); - add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK); + add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK); + add_menu_item_tr(menuFormat, ID_FORMAT_UNDERLINE, "underline", "underline", wxITEM_CHECK); add_menu_item_tr(menuFormat, ID_FORMAT_SYMBOL, "symbol", "symbols", wxITEM_CHECK); add_menu_item_tr(menuFormat, ID_FORMAT_REMINDER, "reminder", "reminder_text", wxITEM_CHECK); mb->Insert(2, menuFormat, _MENU_("format")); @@ -53,7 +55,8 @@ void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { void SetInfoPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { // Toolbar tb->DeleteTool(ID_FORMAT_BOLD); - tb->DeleteTool(ID_FORMAT_ITALIC); + tb->DeleteTool(ID_FORMAT_ITALIC); + tb->DeleteTool(ID_FORMAT_UNDERLINE); tb->DeleteTool(ID_FORMAT_SYMBOL); tb->DeleteTool(ID_FORMAT_REMINDER); // Menus @@ -62,7 +65,7 @@ void SetInfoPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { void SetInfoPanel::onUpdateUI(wxUpdateUIEvent& ev) { switch (ev.GetId()) { - case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { + case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { ev.Enable(editor->canFormat(ev.GetId())); ev.Check (editor->hasFormat(ev.GetId())); break; @@ -72,7 +75,7 @@ void SetInfoPanel::onUpdateUI(wxUpdateUIEvent& ev) { void SetInfoPanel::onCommand(int id) { switch (id) { - case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { + case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: { editor->doFormat(id); break; } diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp index cb705b27..703cb0e7 100644 --- a/src/gui/value/text.cpp +++ b/src/gui/value/text.cpp @@ -805,7 +805,7 @@ bool TextValueEditor::doDelete() { bool TextValueEditor::canFormat(int type) const { switch (type) { - case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: + case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: return !style().always_symbol && style().allow_formating; case ID_FORMAT_SYMBOL: return !style().always_symbol && style().allow_formating && style().symbol_font.valid(); @@ -822,7 +822,9 @@ bool TextValueEditor::hasFormat(int type) const { case ID_FORMAT_BOLD: return is_in_tag(value().value(), _(""), _("")), - italic(_(""), _("")), + italic(_(""), _("")), + underline(_(""), _("")), symbol(_(""), _("")); TagStack tags; String symbols; @@ -224,7 +225,11 @@ String to_html(const String& str_in, const SymbolFontP& symbol_font, double symb } else if (is_substr(str, i, _("i"))) { tags.open (ret, italic); } else if (is_substr(str, i, _("/i"))) { - tags.close(ret, italic); + tags.close(ret, italic); + } else if (is_substr(str, i, _("u"))) { + tags.open(ret, underline); + } else if (is_substr(str, i, _("/u"))) { + tags.close(ret, underline); } else if (is_substr(str, i, _("sym"))) { tags.open (ret, symbol); } else if (is_substr(str, i, _("/sym"))) { @@ -300,7 +305,8 @@ String to_bbcode(const String& str_in) { String str = remove_tag_contents(str_in,_(" Date: Tue, 26 Jul 2022 22:41:10 -0400 Subject: [PATCH 3/4] misc: adjust text formatting in tagged_string --- src/util/tagged_string.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/util/tagged_string.cpp b/src/util/tagged_string.cpp index 9ad82a81..3be0e892 100644 --- a/src/util/tagged_string.cpp +++ b/src/util/tagged_string.cpp @@ -645,7 +645,10 @@ String simplify_tagged(const String& str) { // (where is the negation of tag) bool add_or_cancel_tag(const String& tag, String& stack, bool all = false) { if (all || starts_with(tag, _("/")) || - starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym")) || starts_with(tag, _("u"))) { + starts_with(tag, _("b")) || + starts_with(tag, _("i")) || + starts_with(tag, _("u")) || + starts_with(tag, _("sym"))) { // cancel out all close tags, but not all open tags, // so is always removed // but is not @@ -692,8 +695,10 @@ String simplify_tagged_overlap(const String& str) { Char c = str.GetChar(i); if (c == _('<')) { String tag = tag_at(str, i); - if (starts_with(tag, _("b")) || starts_with(tag, _("i")) || starts_with(tag, _("sym")) || starts_with(tag, _("u")) || - starts_with(tag, _("/b")) || starts_with(tag, _("/i")) || starts_with(tag, _("/sym")) || starts_with(tag, _("/u"))) { + if (starts_with(tag, _("b")) || starts_with(tag, _("/b")) || + starts_with(tag, _("i")) || starts_with(tag, _("/i")) || + starts_with(tag, _("u")) || starts_with(tag, _("/u")) || + starts_with(tag, _("sym")) || starts_with(tag, _("/sym"))) { // optimize this tag if (open_tags.find(_("<") + tag + _(">")) == String::npos) { // we are not already inside this tag From 51925e9ca75fe851e7ef167445d0f15f4365fb2b Mon Sep 17 00:00:00 2001 From: Brendan Hagan Date: Wed, 27 Jul 2022 20:28:10 -0400 Subject: [PATCH 4/4] misc: changelog entry for underline --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index c7682251..48ef400e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ HEAD: new items added as changes are made ------------------------------------------------------------------------------ Features: + * Add ability to underline text using `` tags or panel buttons/hotkeys. (haganbmj#30) Bug fixes: