From: Bowon Ryu Date: Thu, 12 Oct 2023 11:51:14 +0000 (+0900) Subject: Add color tag for text markup anchor X-Git-Tag: dali_2.2.49~5^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=8272ed044bd7789ad9abedae32a470018df04364 Add color tag for text markup anchor "TIZEN" user can set color and clicked color in the anchor tag. if not set, default color is applied. Change-Id: I6ed67b3ae4bec414e306d46bc2b70d4c7a87cdf7 Signed-off-by: Bowon Ryu --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 8db73dd..b7ddaa7 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -2485,7 +2485,7 @@ int UtcDaliToolkitTextlabelAnchorClicked(void) // sets anchor text label.SetProperty(TextLabel::Property::ENABLE_MARKUP, true); - label.SetProperty(TextLabel::Property::TEXT, "TIZEN"); + label.SetProperty(TextLabel::Property::TEXT, "TIZEN"); label.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); label.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); label.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); diff --git a/dali-toolkit/internal/text/anchor.h b/dali-toolkit/internal/text/anchor.h index d2c7384..f23f08a 100644 --- a/dali-toolkit/internal/text/anchor.h +++ b/dali-toolkit/internal/text/anchor.h @@ -35,6 +35,11 @@ struct Anchor CharacterIndex startIndex; ///< The character's start index of the anchor within the string. CharacterIndex endIndex; ///< The character's end index of the anchor within the string. char* href; ///< The url path + + bool isClicked = false; ///< Whether the anchor is clicked or not. + Vector4 clickedColor = Color::DARK_MAGENTA; ///< The color of the anchor when clicked. + uint32_t colorRunIndex; ///< RunIndex of color run, used to change color when clicked. + uint32_t underlinedCharacterRunIndex; ///< RunIndex of underline run, used to change color when clicked. }; } // namespace Text diff --git a/dali-toolkit/internal/text/controller/text-controller-event-handler.cpp b/dali-toolkit/internal/text/controller/text-controller-event-handler.cpp index 78b1693..8e175b1 100644 --- a/dali-toolkit/internal/text/controller/text-controller-event-handler.cpp +++ b/dali-toolkit/internal/text/controller/text-controller-event-handler.cpp @@ -392,14 +392,37 @@ void Controller::EventHandler::AnchorEvent(Controller& controller, float x, floa CharacterHitTest::TAP, matchedCharacter); - for(const auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors) + for(auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors) { // Anchor clicked if the calculated cursor position is within the range of anchor. if(cursorPosition >= anchor.startIndex && cursorPosition < anchor.endIndex) { - if(controller.mImpl->mAnchorControlInterface && anchor.href) + if(controller.mImpl->mAnchorControlInterface) { - std::string href(anchor.href); + if(!anchor.isClicked) + { + anchor.isClicked = true; + // TODO: in mutable text, the anchor color and underline run index should be able to be updated. + if(!controller.IsEditable()) + { + if(controller.mImpl->mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex) + { + ColorRun& colorRun = *(controller.mImpl->mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex); + colorRun.color = anchor.clickedColor; + } + if(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex) + { + UnderlinedCharacterRun& underlineRun = *(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex); + underlineRun.properties.color = anchor.clickedColor; + } + + controller.mImpl->ClearFontData(); + controller.mImpl->mOperationsPending = static_cast(controller.mImpl->mOperationsPending | COLOR); + controller.mImpl->RequestRelayout(); + } + } + + std::string href = anchor.href == nullptr ? "" : anchor.href; controller.mImpl->mAnchorControlInterface->AnchorClicked(href); break; } diff --git a/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.cpp b/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.cpp index 87789e3..d958d19 100644 --- a/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.cpp +++ b/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.cpp @@ -24,6 +24,8 @@ // INTERNAL INCLUDES #include +#include +#include #include #include @@ -33,10 +35,12 @@ namespace Toolkit { namespace Text { -void ProcessAnchor(const Tag& tag, Anchor& anchor) -{ - anchor.href = nullptr; +void ProcessAnchorTag(const Tag& tag, + Anchor& anchor, + ColorRun& colorRun, + UnderlinedCharacterRun& underlinedCharacterRun) +{ for(auto&& attribute : tag.attributes) { if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::HREF, attribute.nameBuffer, attribute.nameLength)) @@ -47,6 +51,15 @@ void ProcessAnchor(const Tag& tag, Anchor& anchor) anchor.href[hrefLength - 1] = '\0'; // The memory is freed when the font run is removed from the logical model. } + else if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength)) + { + ProcessColor(attribute, colorRun); + ProcessColorAttribute(attribute, underlinedCharacterRun); + } + else if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::CLICKED_COLOR, attribute.nameBuffer, attribute.nameLength)) + { + ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, anchor.clickedColor); + } } } diff --git a/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h b/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h index 5559e0a..1fca0c0 100644 --- a/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h +++ b/dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h @@ -18,6 +18,9 @@ * */ +#include +#include + namespace Dali { @@ -35,8 +38,13 @@ struct Anchor; * * @param[in] tag The anchor tag and its attributes. * @param[in,out] anchor The anchor. + * @param[out] colorRun the color run to be filled. + * @param[out] underlinedCharacterRun the underlined character run to be filled. */ -void ProcessAnchor( const Tag& tag, Anchor& anchor ); +void ProcessAnchorTag(const Tag& tag, + Anchor& anchor, + ColorRun& colorRun, + UnderlinedCharacterRun& underlinedCharacterRun); } // namespace Text diff --git a/dali-toolkit/internal/text/markup-processor/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor/markup-processor.cpp index b19cdb1..67037e4 100644 --- a/dali-toolkit/internal/text/markup-processor/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor/markup-processor.cpp @@ -139,6 +139,15 @@ struct Span }; /** + * @brief Struct used to retrieve anchors from the mark-up string. + */ +struct AnchorForStack +{ + RunIndex colorRunIndex; + RunIndex underlinedCharacterRunIndex; +}; + +/** * @brief Initializes a font run description to its defaults. * * @param[in,out] fontRun The font description run to initialize. @@ -210,6 +219,17 @@ void Initialize(Span& span) } /** + * @brief Initializes a anchor to its defaults. + * + * @param[in,out] anchor The anchor to be initialized. + */ +void Initialize(AnchorForStack& anchor) +{ + anchor.colorRunIndex = 0u; + anchor.underlinedCharacterRunIndex = 0u; +} + +/** * @brief Initializes a strikethrough character run to its defaults. * * @param[in,out] strikethroughCharacterRun The strikethrough character run to initialize. @@ -695,38 +715,6 @@ void ProcessParagraphTag( } /** - * @brief Processes the anchor tag - * - * @param[in/out] markupProcessData The markup process data - * @param[in] tag The current tag - * @param[in/out] characterIndex The current character index - */ -void ProcessAnchorTag( - MarkupProcessData& markupProcessData, - const Tag tag, - CharacterIndex& characterIndex) -{ - if(!tag.isEndTag) - { - // Create an anchor instance. - Anchor anchor; - anchor.startIndex = characterIndex; - anchor.endIndex = 0u; - ProcessAnchor(tag, anchor); - markupProcessData.anchors.PushBack(anchor); - } - else - { - // Update end index. - unsigned int count = markupProcessData.anchors.Count(); - if(count > 0) - { - markupProcessData.anchors[count - 1].endIndex = characterIndex; - } - } -} - -/** * @brief Processes span tag for the color-run & font-run. * * @param[in] spanTag The tag we are currently processing @@ -911,6 +899,105 @@ void ProcessSpanForRun( } /** + * @brief Processes anchor tag for the color-run & underline-run. + * + * @param[in,out] markupProcessData The markup process data + * @param[in] tag The tag we are currently processing + * @param[in,out] anchorStack The anchors stack + * @param[in,out] colorRuns The container containing all the color runs + * @param[in,out] underlinedCharacterRuns The container containing all the underlined character runs + * @param[in,out] colorRunIndex The color run index + * @param[in,out] underlinedCharacterRunIndex The underlined character run index + * @param[in] characterIndex The current character index + * @param[in] tagReference The tagReference we should increment/decrement + */ +void ProcessAnchorForRun( + MarkupProcessData& markupProcessData, + const Tag& tag, + StyleStack& anchorStack, + Vector& colorRuns, + Vector& underlinedCharacterRuns, + RunIndex& colorRunIndex, + RunIndex& underlinedCharacterRunIndex, + const CharacterIndex characterIndex, + int& tagReference) +{ + if(!tag.isEndTag) + { + // Create an anchor instance. + Anchor anchor; + anchor.href = nullptr; + anchor.startIndex = characterIndex; + anchor.endIndex = 0u; + anchor.colorRunIndex = colorRunIndex; + anchor.underlinedCharacterRunIndex = underlinedCharacterRunIndex; + + // Create a new run. + ColorRun colorRun; + Initialize(colorRun); + + UnderlinedCharacterRun underlinedCharacterRun; + Initialize(underlinedCharacterRun); + + AnchorForStack anchorForStack; + Initialize(anchorForStack); + + // Fill the run with the parameters. + colorRun.characterRun.characterIndex = characterIndex; + underlinedCharacterRun.characterRun.characterIndex = characterIndex; + + anchorForStack.colorRunIndex = colorRunIndex; + anchorForStack.underlinedCharacterRunIndex = underlinedCharacterRunIndex; + + // Init default color + colorRun.color = Color::MEDIUM_BLUE; + underlinedCharacterRun.properties.color = Color::MEDIUM_BLUE; + underlinedCharacterRun.properties.colorDefined = true; + + ProcessAnchorTag(tag, anchor, colorRun, underlinedCharacterRun); + + markupProcessData.anchors.PushBack(anchor); + + // Push the anchor into the stack. + anchorStack.Push(anchorForStack); + + // Push the run in the logical model. + colorRuns.PushBack(colorRun); + ++colorRunIndex; + + // Push the run in the logical model. + underlinedCharacterRuns.PushBack(underlinedCharacterRun); + ++underlinedCharacterRunIndex; + + // Increase reference + ++tagReference; + } + else + { + if(tagReference > 0) + { + // Update end index. + unsigned int count = markupProcessData.anchors.Count(); + if(count > 0) + { + markupProcessData.anchors[count - 1].endIndex = characterIndex; + } + + // Pop the top of the stack and set the number of characters of the run. + AnchorForStack anchorForStack = anchorStack.Pop(); + + ColorRun& colorRun = *(colorRuns.Begin() + anchorForStack.colorRunIndex); + colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex; + + UnderlinedCharacterRun& underlinedCharacterRun = *(underlinedCharacterRuns.Begin() + anchorForStack.underlinedCharacterRunIndex); + underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex; + + --tagReference; + } + } +} + +/** * @brief Resizes the model's vectors * * @param[inout] markupProcessData The markup process data @@ -1060,6 +1147,8 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar // Stores a struct with the index to the first character of the color run & color font for the span. StyleStack spanStack; + StyleStack anchorStack; + // Points the next free position in the vector of runs. RunIndex colorRunIndex = 0u; RunIndex fontRunIndex = 0u; @@ -1080,6 +1169,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar int sTagReference = 0u; int pTagReference = 0u; int characterSpacingTagReference = 0u; + int aTagReference = 0u; // Give an initial default value to the model's vectors. markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE); @@ -1135,21 +1225,15 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar } // else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length)) { - /* Anchor */ - ProcessAnchorTag(markupProcessData, tag, characterIndex); - /* Color */ - ProcessTagForRun( - markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { - run.color = Color::BLUE; - ProcessColorTag(tag, run); - }); - /* Underline */ - ProcessTagForRun( - markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { - run.properties.color = Color::BLUE; - run.properties.colorDefined = true; - ProcessUnderlineTag(tag, run); - }); + ProcessAnchorForRun(markupProcessData, + tag, + anchorStack, + markupProcessData.colorRuns, + markupProcessData.underlinedCharacterRuns, + colorRunIndex, + underlinedCharacterRunIndex, + characterIndex, + aTagReference); } // tizen else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length)) { diff --git a/dali-toolkit/internal/text/markup-tags-and-attributes.h b/dali-toolkit/internal/text/markup-tags-and-attributes.h index 0f75d6a..0cc21c0 100644 --- a/dali-toolkit/internal/text/markup-tags-and-attributes.h +++ b/dali-toolkit/internal/text/markup-tags-and-attributes.h @@ -706,6 +706,16 @@ namespace ANCHOR_ATTRIBUTES */ static const std::string HREF("href"); +/** + * @brief Sets the color for the characters and underlines inside the element. + */ +static const std::string COLOR("color"); + +/** + * @brief Sets the clicked color for the characters and underlines inside the element. + */ +static const std::string CLICKED_COLOR("clicked-color"); + } // namespace ANCHOR_ATTRIBUTES } // namespace MARKUP