From 23b60af529becdd828c034b8d0df39c232df0123 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Mon, 24 Nov 2025 17:45:21 +0300 Subject: [PATCH] Add text highlight --- src/DrawingProgram/TextBoxEditTool.cpp | 28 ++++++++++++++++++++++ src/DrawingProgram/TextBoxEditTool.hpp | 1 + src/RichText/TextBox.cpp | 17 ++++++------- src/RichText/TextStyleModifier.cpp | 33 ++++++++++++++++++++++++++ src/RichText/TextStyleModifier.hpp | 15 ++++++++++++ 5 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/DrawingProgram/TextBoxEditTool.cpp b/src/DrawingProgram/TextBoxEditTool.cpp index 3cfa714..6fa56d7 100644 --- a/src/DrawingProgram/TextBoxEditTool.cpp +++ b/src/DrawingProgram/TextBoxEditTool.cpp @@ -90,6 +90,7 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { else release_undo_data("Font Size"); + // Text color 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)) @@ -108,6 +109,32 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr& comp) { a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::COLOR]); } + + + // Highlight color + 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("Highlight Color", &newHighlightColor, &newHighlightColor == t.colorRight)) { + if(newHighlightColor.w() == 0.0f) // Make highlight appear when the button is pressed + newHighlightColor.w() = 1.0f; + t.color_selector_right(&newHighlightColor == t.colorRight ? nullptr : &newHighlightColor); + } + } + t.gui.text_label("Highlight Color"); + }); + + if(&newHighlightColor == t.colorRight) + hold_undo_data("Highlight Color", a); + else + release_undo_data("Highlight Color"); + + if((&newHighlightColor == t.colorRight) && t.isUpdatingColorRight) { + currentMods[TextStyleModifier::ModifierType::HIGHLIGHT_COLOR] = std::make_shared(newHighlightColor); + a->textBox->set_text_style_modifier_between(a->cursor->selectionBeginPos, a->cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::HIGHLIGHT_COLOR]); + } + + + t.gui.pop_id(); if(a->textBox->inputChangedTextBox) @@ -176,6 +203,7 @@ void TextBoxEditTool::set_styles_at_selection(const std::shared_ptr newFontName = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES])->get_families().back().c_str(); newFontSize = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::SIZE])->get_size(); newTextColor = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::COLOR])->get_color(); + newHighlightColor = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::HIGHLIGHT_COLOR])->get_color(); newIsBold = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::WEIGHT])->get_weight() == SkFontStyle::Weight::kBold_Weight; newIsItalic = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::SLANT])->get_slant() == SkFontStyle::Slant::kItalic_Slant; newIsUnderlined = std::static_pointer_cast(currentMods[TextStyleModifier::ModifierType::DECORATION])->get_decoration_value() & skia::textlayout::TextDecoration::kUnderline; diff --git a/src/DrawingProgram/TextBoxEditTool.hpp b/src/DrawingProgram/TextBoxEditTool.hpp index 0dd4ff8..1e34dd1 100644 --- a/src/DrawingProgram/TextBoxEditTool.hpp +++ b/src/DrawingProgram/TextBoxEditTool.hpp @@ -22,6 +22,7 @@ class TextBoxEditTool : public DrawingProgramEditToolBase { uint32_t newFontSize = 15; Vector4f newTextColor{1.0f, 1.0f, 1.0f, 1.0f}; + Vector4f newHighlightColor{1.0f, 1.0f, 1.0f, 0.0f}; bool newIsBold = false; bool newIsItalic = false; bool newIsUnderlined = false; diff --git a/src/RichText/TextBox.cpp b/src/RichText/TextBox.cpp index fb14d73..af3fc32 100644 --- a/src/RichText/TextBox.cpp +++ b/src/RichText/TextBox.cpp @@ -1042,7 +1042,7 @@ SkRect TextBox::get_cursor_rect(TextPosition pos) { } } - constexpr float CURSOR_WIDTH = 3.0f; + constexpr float CURSOR_WIDTH = 2.0f; return SkRect::MakeXYWH(topPoint.x() - CURSOR_WIDTH * 0.5f, topPoint.y(), CURSOR_WIDTH, height); } @@ -1103,21 +1103,22 @@ std::pair TextBox::get_start_end_paragraph_pos(size_t p1, size_t void TextBox::paint(SkCanvas* canvas, const PaintOpts& paintOpts) { rebuild(); + for(auto& pData : paragraphs) + pData.p->paint(canvas, 0.0f, pData.heightOffset); + if(paintOpts.cursor.has_value()) { auto& cur = paintOpts.cursor.value(); - SkPaint p{SkColor4f{paintOpts.cursorColor.x(), paintOpts.cursorColor.y(), paintOpts.cursorColor.z(), 1.0f}}; + SkPaint selectionP{SkColor4f{paintOpts.cursorColor.x(), paintOpts.cursorColor.y(), paintOpts.cursorColor.z(), 1.0f}}; if(cur.selectionBeginPos != cur.selectionEndPos) { - canvas->saveLayerAlphaf(nullptr, 0.6f); + canvas->saveLayerAlphaf(nullptr, 0.3f); rects_between_text_positions_func(cur.selectionBeginPos, cur.selectionEndPos, [&](const SkRect& rect) { - canvas->drawRect(rect, p); + canvas->drawRect(rect, selectionP); }); canvas->restore(); } - canvas->drawRect(get_cursor_rect(cur.pos), p); + SkPaint cursorP{SkColor4f{paintOpts.cursorColor.x(), paintOpts.cursorColor.y(), paintOpts.cursorColor.z(), 0.8f}}; + canvas->drawRect(get_cursor_rect(cur.pos), cursorP); } - - for(auto& pData : paragraphs) - pData.p->paint(canvas, 0.0f, pData.heightOffset); } } diff --git a/src/RichText/TextStyleModifier.cpp b/src/RichText/TextStyleModifier.cpp index f268471..788118a 100644 --- a/src/RichText/TextStyleModifier.cpp +++ b/src/RichText/TextStyleModifier.cpp @@ -25,6 +25,8 @@ std::shared_ptr TextStyleModifier::allocate_modifier(Modifier return std::make_shared(); case ModifierType::FONT_FAMILIES: return std::make_shared(); + case ModifierType::HIGHLIGHT_COLOR: + return std::make_shared(); case ModifierType::COUNT: return nullptr; } @@ -44,6 +46,7 @@ const TextStyleModifier::ModifierMap& TextStyleModifier::get_default_modifiers() defaultMods[ModifierType::WEIGHT] = std::make_shared(SkFontStyle::kNormal_Weight); defaultMods[ModifierType::SLANT] = std::make_shared(SkFontStyle::kUpright_Slant); defaultMods[ModifierType::DECORATION] = std::make_shared(skia::textlayout::TextDecoration::kNoDecoration); + defaultMods[ModifierType::HIGHLIGHT_COLOR] = std::make_shared(Vector4f{0.0f, 0.0f, 0.0f, 0.0f}); } return defaultMods; } @@ -231,4 +234,34 @@ bool DecorationTextStyleModifier::equivalent_data(TextStyleModifier& modifier) c return decorationValue == static_cast(modifier).decorationValue; } + +HighlightColorTextStyleModifier::HighlightColorTextStyleModifier(const Vector4f& initColor): color(initColor) {} + +TextStyleModifier::ModifierType HighlightColorTextStyleModifier::get_type() const { + return ModifierType::HIGHLIGHT_COLOR; +} + +const Vector4f& HighlightColorTextStyleModifier::get_color() const { + return color; +} + +void HighlightColorTextStyleModifier::save(cereal::PortableBinaryOutputArchive& a) const { + a(color); +} + +void HighlightColorTextStyleModifier::load(cereal::PortableBinaryInputArchive& a) { + a(color); +} + +void HighlightColorTextStyleModifier::modify_text_style(skia::textlayout::TextStyle& style) const { + if(color.w() == 0.0f) + style.clearBackgroundColor(); + else + style.setBackgroundPaint(SkPaint{convert_vec4(color)}); +} + +bool HighlightColorTextStyleModifier::equivalent_data(TextStyleModifier& modifier) const { + return color == static_cast(modifier).color; +} + } diff --git a/src/RichText/TextStyleModifier.hpp b/src/RichText/TextStyleModifier.hpp index 9d37981..edc208c 100644 --- a/src/RichText/TextStyleModifier.hpp +++ b/src/RichText/TextStyleModifier.hpp @@ -17,6 +17,7 @@ class TextStyleModifier { SLANT, DECORATION, FONT_FAMILIES, + HIGHLIGHT_COLOR, COUNT }; @@ -93,6 +94,20 @@ class ColorTextStyleModifier : public TextStyleModifier { virtual bool equivalent_data(TextStyleModifier& modifier) const override; }; +class HighlightColorTextStyleModifier : public TextStyleModifier { + public: + HighlightColorTextStyleModifier() = default; + HighlightColorTextStyleModifier(const Vector4f& initColor); + virtual ModifierType get_type() const override; + virtual void save(cereal::PortableBinaryOutputArchive& a) const override; + virtual void load(cereal::PortableBinaryInputArchive& a) override; + virtual void modify_text_style(skia::textlayout::TextStyle& style) const override; + const Vector4f& get_color() const; + private: + Vector4f color; + virtual bool equivalent_data(TextStyleModifier& modifier) const override; +}; + class SizeTextStyleModifier : public TextStyleModifier { public: SizeTextStyleModifier() = default;