diff --git a/src/DrawComponents/DrawTextBox.cpp b/src/DrawComponents/DrawTextBox.cpp index 6f71369..f17b19e 100644 --- a/src/DrawComponents/DrawTextBox.cpp +++ b/src/DrawComponents/DrawTextBox.cpp @@ -12,7 +12,23 @@ DrawTextBox::DrawTextBox(): textBox(std::make_shared()), cursor(std::make_shared()) -{} +{ + skia::textlayout::TextStyle tStyle; + tStyle.setFontFamilies({SkString{"Roboto"}}); + tStyle.setFontSize(16.0f); + tStyle.setForegroundPaint(SkPaint{SkColor4f{0.0f, 1.0f, 1.0f, 1.0f}}); + textBox->set_initial_text_style(tStyle); + + auto boldMod = std::make_shared(); + boldMod->set_weight(SkFontStyle::kNormal_Weight); + textBox->set_initial_text_style_modifier(boldMod); + auto italicMod = std::make_shared(); + italicMod->set_slant(SkFontStyle::Slant::kUpright_Slant); + textBox->set_initial_text_style_modifier(italicMod); + auto colorMod = std::make_shared(); + colorMod->color = {1.0f, 1.0f, 1.0f, 1.0f}; + textBox->set_initial_text_style_modifier(colorMod); +} DrawComponentType DrawTextBox::get_type() const { return DRAWCOMPONENT_TEXTBOX; @@ -54,20 +70,6 @@ void DrawTextBox::update_from_delayed_ptr(const std::shared_ptr& void DrawTextBox::init_text_box(DrawingProgram& drawP) { textBox->set_font_collection(drawP.world.main.fonts.collection); // Getting a segfault relating to the paragraph cache means that the font collection hasn't been set yet textBox->set_width(d.p2.x() - d.p1.x()); - skia::textlayout::TextStyle tStyle; - tStyle.setFontFamilies({SkString{"Roboto"}}); - tStyle.setFontSize(16.0f); - textBox->set_initial_text_style(tStyle); - - auto boldMod = std::make_shared(); - boldMod->set_weight(SkFontStyle::kNormal_Weight); - textBox->set_initial_text_style_modifier(boldMod); - auto italicMod = std::make_shared(); - italicMod->set_slant(SkFontStyle::Slant::kUpright_Slant); - textBox->set_initial_text_style_modifier(italicMod); - auto colorMod = std::make_shared(); - colorMod->color = {1.0f, 1.0f, 1.0f, 1.0f}; - textBox->set_initial_text_style_modifier(colorMod); } void DrawTextBox::draw(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/RichTextBox/RichTextBox.cpp b/src/RichTextBox/RichTextBox.cpp index ba57407..1aa356b 100644 --- a/src/RichTextBox/RichTextBox.cpp +++ b/src/RichTextBox/RichTextBox.cpp @@ -336,6 +336,7 @@ void RichTextBox::set_initial_text_style_modifier(const std::shared_ptrget_type()] = modifier; + remove_duplicate_text_style_mods(); } std::shared_ptr RichTextBox::get_last_text_style_mod_before_pos(TextPosition pos, TextStyleModifier::ModifierType modType) { @@ -376,22 +377,32 @@ void RichTextBox::set_text_style_modifier_between(TextPosition p1, TextPosition return p >= start && modifier->get_type() == modToCheck->get_type(); }); insert_style_at_pos(start, modifier); - insert_style_at_pos(end, lastModOfThisTypeBeforeEnd); + if(end != move(Movement::END, {0, 0})) + insert_style_at_pos(end, lastModOfThisTypeBeforeEnd); + remove_duplicate_text_style_mods(); needsRebuild = true; } } void RichTextBox::insert_style_at_pos(TextPosition pos, const std::shared_ptr& modifier) { size_t indexToPlaceAt = 0; + bool finishedInsertingStyle = false; for(auto& [tPos, tStyleModsInPos] : tStyleMods) { if(tPos > pos) break; - else if(tPos == pos) + else if(tPos == pos) { tStyleModsInPos[modifier->get_type()] = modifier; - indexToPlaceAt++; + finishedInsertingStyle = true; + break; + } + else + indexToPlaceAt++; + } + if(!finishedInsertingStyle) { + auto it = tStyleMods.insert(tStyleMods.begin() + indexToPlaceAt, PositionedTextStyleMod{}); + it->pos = pos; + it->mods[modifier->get_type()] = modifier; } - auto it = tStyleMods.insert(tStyleMods.begin() + indexToPlaceAt, PositionedTextStyleMod{pos}); - it->mods[modifier->get_type()] = modifier; } RichTextBox::TextPosition RichTextBox::move(Movement movement, TextPosition pos, std::optional* previousX, bool flipDependingOnTextDirection) { @@ -615,6 +626,7 @@ void RichTextBox::rebuild() { auto& nextTStyleMod = *nextTStyleModIt; // Print with previous style + a.pushStyle(tStyle); a.addText(pData.text.c_str() + tIndex, nextTStyleMod.pos.fTextByteIndex - tIndex); a.pop(); @@ -634,10 +646,30 @@ void RichTextBox::rebuild() { heightOffset += pData.p->getHeight(); } + //std::cout << "size: " << tStyleMods.size() << std::endl; + //for(auto& s : tStyleMods) + // std::cout << s.pos.fParagraphIndex << " " << s.pos.fTextByteIndex << std::endl; + needsRebuild = false; } } +void RichTextBox::remove_duplicate_text_style_mods() { + std::unordered_map> previouslyAppliedMods; + std::erase_if(tStyleMods, [&previouslyAppliedMods](PositionedTextStyleMod& tStyleModsInPos) { + std::erase_if(tStyleModsInPos.mods, [&previouslyAppliedMods](const std::pair>& tStyleModPair) { + auto [placedIt, insertionTookPlace] = previouslyAppliedMods.emplace(tStyleModPair.first, tStyleModPair.second); + if(!insertionTookPlace) { + if(placedIt->second->equivalent(*tStyleModPair.second)) + return true; + placedIt->second = tStyleModPair.second; + } + return false; + }); + return tStyleModsInPos.mods.empty(); + }); +} + void RichTextBox::set_tab_space_width(unsigned newTabWidth) { tabWidth = newTabWidth; } @@ -651,7 +683,7 @@ RichTextBox::TextPosition RichTextBox::insert(TextPosition pos, std::string_view for(auto& [p, tStylesInPos] : tStyleMods) { if(p.fParagraphIndex > pos.fParagraphIndex) p.fParagraphIndex++; - else if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex) { + else if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex && !(p.fTextByteIndex == pos.fTextByteIndex && p.fTextByteIndex == 0)) { p.fTextByteIndex = p.fTextByteIndex - pos.fTextByteIndex; p.fParagraphIndex++; } @@ -665,7 +697,7 @@ RichTextBox::TextPosition RichTextBox::insert(TextPosition pos, std::string_view } else if(c == '\t') { for(auto& [p, tStylesInPos] : tStyleMods) { - if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex) + if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex && !(p.fTextByteIndex == pos.fTextByteIndex && p.fTextByteIndex == 0)) p.fTextByteIndex += tabWidth; } paragraphs[pos.fParagraphIndex].text.insert(pos.fTextByteIndex, std::string(tabWidth, ' ')); @@ -673,7 +705,7 @@ RichTextBox::TextPosition RichTextBox::insert(TextPosition pos, std::string_view } else { for(auto& [p, tStylesInPos] : tStyleMods) { - if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex) + if(p.fParagraphIndex == pos.fParagraphIndex && p.fTextByteIndex >= pos.fTextByteIndex && !(p.fTextByteIndex == pos.fTextByteIndex && p.fTextByteIndex == 0)) p.fTextByteIndex++; } paragraphs[pos.fParagraphIndex].text.insert(paragraphs[pos.fParagraphIndex].text.begin() + pos.fTextByteIndex, c); @@ -681,7 +713,11 @@ RichTextBox::TextPosition RichTextBox::insert(TextPosition pos, std::string_view } } - needsRebuild = true; + if(!textToInsert.empty()) { + remove_duplicate_text_style_mods(); + needsRebuild = true; + } + return pos; } @@ -705,8 +741,6 @@ RichTextBox::TextPosition RichTextBox::remove(TextPosition p1, TextPosition p2) paragraphs.erase(paragraphs.begin() + start.fParagraphIndex + 1, paragraphs.begin() + end.fParagraphIndex + 1); } - std::optional prevTextStyleModIndex; - for(int32_t i = 0; i < static_cast(tStyleMods.size()); i++) { PositionedTextStyleMod& tStyleMod = tStyleMods[i]; auto& p = tStyleMod.pos; @@ -722,8 +756,8 @@ RichTextBox::TextPosition RichTextBox::remove(TextPosition p1, TextPosition p2) else p.fParagraphIndex -= (end.fParagraphIndex - start.fParagraphIndex); } - if(prevTextStyleModIndex.has_value() && tStyleMods[prevTextStyleModIndex.value()].pos == p) { - auto& tStyleModsToMergeWith = tStyleMods[prevTextStyleModIndex.value()].mods; + if(i > 0 && tStyleMods[i - 1].pos == p) { + auto& tStyleModsToMergeWith = tStyleMods[i - 1].mods; for(auto& [modType, tStyle] : tStyleMod.mods) tStyleModsToMergeWith[modType] = tStyle; tStyleMods.erase(tStyleMods.begin() + i); @@ -731,7 +765,9 @@ RichTextBox::TextPosition RichTextBox::remove(TextPosition p1, TextPosition p2) } } + remove_duplicate_text_style_mods(); needsRebuild = true; + return start; } diff --git a/src/RichTextBox/RichTextBox.hpp b/src/RichTextBox/RichTextBox.hpp index ab6c06e..ebc106d 100644 --- a/src/RichTextBox/RichTextBox.hpp +++ b/src/RichTextBox/RichTextBox.hpp @@ -131,6 +131,8 @@ class RichTextBox { void erase_if_over_all_styles_until_pos(TextPosition pos, const std::function&)>& func); void insert_style_at_pos(TextPosition pos, const std::shared_ptr& modifier); + void remove_duplicate_text_style_mods(); + void rebuild(); bool newlinesAllowed = true;