diff --git a/src/DrawingProgram/TextBoxEditTool.cpp b/src/DrawingProgram/TextBoxEditTool.cpp index c7c6411..fd1e7e1 100644 --- a/src/DrawingProgram/TextBoxEditTool.cpp +++ b/src/DrawingProgram/TextBoxEditTool.cpp @@ -21,7 +21,6 @@ TextBoxEditTool::TextBoxEditTool(DrawingProgram& initDrawP): {} bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { - std::shared_ptr a = std::static_pointer_cast(comp); Toolbar& t = drawP.world.main.toolbar; @@ -32,7 +31,7 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { t.gui.text_label("Font"); if(t.gui.font_picker("font picker", &newFontName)) { currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES] = std::make_shared(std::vector{SkString{newFontName.c_str(), newFontName.size()}}); - a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES]); + add_undo_if_selecting_area(a, [&]() {a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES]);}); } }); @@ -40,13 +39,13 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { if(t.gui.svg_icon_button("Bold button", "data/icons/RemixIcon/bold.svg", newIsBold)) { newIsBold = !newIsBold; currentMods[TextStyleModifier::ModifierType::WEIGHT] = std::make_shared(newIsBold ? SkFontStyle::Weight::kBold_Weight : SkFontStyle::Weight::kNormal_Weight); - a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::WEIGHT]); + add_undo_if_selecting_area(a, [&]() {a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::WEIGHT]);}); } if(t.gui.svg_icon_button("Italic button", "data/icons/RemixIcon/italic.svg", newIsItalic)) { newIsItalic = !newIsItalic; currentMods[TextStyleModifier::ModifierType::SLANT] = std::make_shared(newIsItalic ? SkFontStyle::Slant::kItalic_Slant : SkFontStyle::Slant::kUpright_Slant); - a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SLANT]); + add_undo_if_selecting_area(a, [&]() {a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SLANT]);}); } bool decorationEdited = false; @@ -64,38 +63,46 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { } if(decorationEdited) { currentMods[TextStyleModifier::ModifierType::DECORATION] = std::make_shared(get_new_decoration_value()); - a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::DECORATION]); + add_undo_if_selecting_area(a, [&]() {a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::DECORATION]);}); } }); t.gui.left_to_right_line_centered_layout([&]() { if(t.gui.svg_icon_button("Align left button", "data/icons/RemixIcon/align-left.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kLeft)) - a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kLeft); + add_undo([&](){a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kLeft);}); if(t.gui.svg_icon_button("Align center button", "data/icons/RemixIcon/align-center.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kCenter)) - a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kCenter); + add_undo([&](){a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kCenter);}); if(t.gui.svg_icon_button("Align right button", "data/icons/RemixIcon/align-right.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kRight)) - a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kRight); + add_undo([&](){a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kRight);}); if(t.gui.svg_icon_button("Align justify button", "data/icons/RemixIcon/align-justify.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kJustify)) - a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kJustify); + add_undo([&](){a->textBox->set_text_alignment_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kJustify);}); if(t.gui.svg_icon_button("Text direction left", "data/icons/RemixIcon/text-direction-l.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kLtr)) - a->textBox->set_text_direction_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kLtr); + add_undo([&](){a->textBox->set_text_direction_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kLtr);}); if(t.gui.svg_icon_button("Text direction right", "data/icons/RemixIcon/text-direction-r.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kRtl)) - a->textBox->set_text_direction_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kRtl); + add_undo([&](){a->textBox->set_text_direction_between(a->cursor->selectionBeginPos.fParagraphIndex, a->cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kRtl);}); }); if(t.gui.slider_scalar_field("Font Size Slider", "Font Size", &newFontSize, 3, 100)) { + hold_undo_data("Font Size", a); currentMods[TextStyleModifier::ModifierType::SIZE] = std::make_shared(newFontSize); a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SIZE]); } + else + release_undo_data("Font Size"); t.gui.left_to_right_line_layout([&]() { CLAY({.layout = {.sizing = {.width = CLAY_SIZING_FIXED(40), .height = CLAY_SIZING_FIXED(40)}}}) { - if(t.gui.color_button("Text Color", &newTextColor, &newTextColor == t.colorRight)) { + if(t.gui.color_button("Text Color", &newTextColor, &newTextColor == t.colorRight)) t.color_selector_right(&newTextColor == t.colorRight ? nullptr : &newTextColor); - } } t.gui.text_label("Text Color"); }); + + if(&newTextColor == t.colorRight) + hold_undo_data("Text Color", a); + else + release_undo_data("Text Color"); + if((&newTextColor == t.colorRight) && t.isUpdatingColorRight) { currentMods[TextStyleModifier::ModifierType::COLOR] = std::make_shared(newTextColor); a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::COLOR]); @@ -112,6 +119,42 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { return oldInputChangedTextBox; } +void TextBoxEditTool::hold_undo_data(const std::string& undoName, const std::shared_ptr& a) { + auto it = undoHeldData.find(undoName); + if(it != undoHeldData.end()) { + std::pair& undoData = it->second; + if(undoData.first != *a->cursor) + undoHeldData.erase(it); + } + else if(a->cursor->selectionBeginPos != a->cursor->selectionEndPos) + undoHeldData.emplace(undoName, std::pair{*a->cursor, a->textBox->get_rich_text_data()}); +} + +void TextBoxEditTool::release_undo_data(const std::string& undoName) { + auto it = undoHeldData.find(undoName); + if(it != undoHeldData.end()) { + std::pair& undoData = it->second; + InputManager& input = drawP.world.main.input; + input.text.add_textbox_undo(undoData.first, undoData.second); + undoHeldData.erase(it); + std::cout << "Yay 2!" << std::endl; + } +} + +void TextBoxEditTool::add_undo_if_selecting_area(const std::shared_ptr& a, const std::function& func) { + if(a->cursor->selectionBeginPos == a->cursor->selectionEndPos) + func(); + else { + InputManager& input = drawP.world.main.input; + input.text.do_textbox_operation_with_undo(func); + } +} + +void TextBoxEditTool::add_undo(const std::function& func) { + InputManager& input = drawP.world.main.input; + input.text.do_textbox_operation_with_undo(func); +} + uint8_t TextBoxEditTool::get_new_decoration_value() { uint8_t toRet = skia::textlayout::TextDecoration::kNoDecoration; if(newIsUnderlined) diff --git a/src/DrawingProgram/TextBoxEditTool.hpp b/src/DrawingProgram/TextBoxEditTool.hpp index d114692..0dd4ff8 100644 --- a/src/DrawingProgram/TextBoxEditTool.hpp +++ b/src/DrawingProgram/TextBoxEditTool.hpp @@ -32,6 +32,14 @@ class TextBoxEditTool : public DrawingProgramEditToolBase { uint8_t get_new_decoration_value(); void set_styles_at_selection(const std::shared_ptr& a); + void add_undo_if_selecting_area(const std::shared_ptr& a, const std::function& func); + void add_undo(const std::function& func); + + void hold_undo_data(const std::string& undoName, const std::shared_ptr& a); + void release_undo_data(const std::string& undoName); + + std::unordered_map> undoHeldData; + RichText::TextStyleModifier::ModifierMap currentMods; std::vector sortedFontList; diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 88fb794..0708b6d 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -107,13 +107,13 @@ void InputManager::Text::add_textbox_undo(const RichText::TextBox::Cursor& prevC if(textBox) { textboxUndo.push({[textBox = textBox, cursor = cursor, prevCursor = prevCursor, prevRichText = prevRichText]() { textBox->set_rich_text_data(prevRichText); - *cursor = prevCursor; + cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(prevCursor.selectionEndPos, prevCursor.selectionBeginPos); cursor->previousX = std::nullopt; return true; }, [textBox = textBox, cursor = cursor, currentCursor = *cursor, currentRichText = textBox->get_rich_text_data()]() { textBox->set_rich_text_data(currentRichText); - *cursor = currentCursor; + cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(currentCursor.selectionEndPos, currentCursor.selectionBeginPos); cursor->previousX = std::nullopt; return true; }}); diff --git a/src/InputManager.hpp b/src/InputManager.hpp index cb62c4f..0126b1e 100644 --- a/src/InputManager.hpp +++ b/src/InputManager.hpp @@ -92,10 +92,10 @@ struct InputManager { void set_rich_text_box_input(const std::shared_ptr& nTextBox, const std::shared_ptr& nCursor, const std::optional& nModMap = std::nullopt); void add_text_to_textbox(const std::string& inputText); - private: - void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText); - void do_textbox_operation_with_undo(const std::function& func); + void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText); + void do_textbox_operation_with_undo(const std::function& func); + private: std::shared_ptr textBox; std::shared_ptr cursor; std::optional modMap; diff --git a/src/RichText/TextBox.cpp b/src/RichText/TextBox.cpp index 9035812..6ef4242 100644 --- a/src/RichText/TextBox.cpp +++ b/src/RichText/TextBox.cpp @@ -98,6 +98,14 @@ bool TextPosition::operator<=(const TextPosition& o) const { return (*this < o) || (*this == o); } +bool TextBox::Cursor::operator==(const Cursor& o) const { + return o.selectionBeginPos == selectionBeginPos && o.selectionEndPos == selectionEndPos && o.pos == pos; +} + +bool TextBox::Cursor::operator!=(const Cursor& o) const { + return !(*this == o); +} + TextBox::TextBox() { paragraphs.emplace_back(); } diff --git a/src/RichText/TextBox.hpp b/src/RichText/TextBox.hpp index 38b6f11..df91308 100644 --- a/src/RichText/TextBox.hpp +++ b/src/RichText/TextBox.hpp @@ -83,8 +83,8 @@ class TextBox { a(pos, selectionBeginPos, selectionEndPos); } std::optional previousX; - bool operator==(const Cursor& o) const = default; - bool operator!=(const Cursor& o) const = default; + bool operator==(const Cursor& o) const; + bool operator!=(const Cursor& o) const; }; struct PaintOpts {