const uint8_t* utf8 = NULL;
if(markupProcessorEnabled)
{
- ProcessMarkupString(text, markupProcessData);
+ MarkupPropertyData markupPropertyData(Color::MEDIUM_BLUE, Color::DARK_MAGENTA);
+
+ ProcessMarkupString(text, markupPropertyData, markupProcessData);
textSize = markupProcessData.markupProcessedText.size();
// This is a bit horrible but std::string returns a (signed) char*
Vector<BoundedParagraphRun> boundedParagraphRuns;
Vector<CharacterSpacingCharacterRun> characterSpacingCharacterRuns;
MarkupProcessData markupProcessData(colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns, strikethroughCharacterRuns, boundedParagraphRuns, characterSpacingCharacterRuns);
- ProcessMarkupString(data.xHTMLEntityString, markupProcessData);
+
+ MarkupPropertyData markupPropertyData(Color::MEDIUM_BLUE, Color::DARK_MAGENTA);
+ ProcessMarkupString(data.xHTMLEntityString, markupPropertyData, markupProcessData);
for(Vector<EmbeddedItem>::Iterator it = items.Begin(),
endIt = items.End();
const char* const PROPERTY_NAME_FONT_SIZE_SCALE = "fontSizeScale";
const char* const PROPERTY_NAME_ENABLE_FONT_SIZE_SCALE = "enableFontSizeScale";
-const char* const PROPERTY_NAME_ELLIPSIS_POSITION = "ellipsisPosition";
+const char* const PROPERTY_NAME_ELLIPSIS_POSITION = "ellipsisPosition";
+const char* const PROPERTY_NAME_ANCHOR_COLOR = "anchorColor";
+const char* const PROPERTY_NAME_ANCHOR_CLICKED_COLOR = "anchorClickedColor";
const std::string DEFAULT_FONT_DIR("/resources/fonts");
const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ENABLE_FONT_SIZE_SCALE) == DevelTextLabel::Property::ENABLE_FONT_SIZE_SCALE);
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ELLIPSIS_POSITION) == DevelTextLabel::Property::ELLIPSIS_POSITION);
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextLabel::Property::STRIKETHROUGH);
+ DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_COLOR) == DevelTextLabel::Property::ANCHOR_COLOR);
+ DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_CLICKED_COLOR) == DevelTextLabel::Property::ANCHOR_CLICKED_COLOR);
END_TEST;
}
label.SetProperty(TextLabel::Property::TEXT_COLOR, Color::BLUE);
DALI_TEST_EQUALS(label.GetProperty<Vector4>(TextLabel::Property::TEXT_COLOR), Color::BLUE, TEST_LOCATION);
+ // Check that anchor color can be properly set
+ label.SetProperty(DevelTextLabel::Property::ANCHOR_COLOR, Color::BLUE);
+ DALI_TEST_EQUALS(label.GetProperty<Vector4>(DevelTextLabel::Property::ANCHOR_COLOR), Color::BLUE, TEST_LOCATION);
+
+ label.SetProperty(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR, Color::RED);
+ DALI_TEST_EQUALS(label.GetProperty<Vector4>(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR), Color::RED, TEST_LOCATION);
+
Property::Map strikethroughMapSet;
Property::Map strikethroughMapGet;
END_TEST;
}
+int UtcDaliToolkitTextlabelAnchorColor(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliToolkitTextlabelAnchorColor");
+ TextLabel label = TextLabel::New();
+ DALI_TEST_CHECK(label);
+
+ application.GetScene().Add(label);
+
+ // connect to the anchor clicked signal.
+ ConnectionTracker* testTracker = new ConnectionTracker();
+ DevelTextLabel::AnchorClickedSignal(label).Connect(&TestAnchorClickedCallback);
+ bool anchorClickedSignal = false;
+ label.ConnectSignal(testTracker, "anchorClicked", CallbackFunctor(&anchorClickedSignal));
+
+ gAnchorClickedCallBackCalled = false;
+ label.SetProperty(TextLabel::Property::TEXT, "<a href='https://www.tizen.org'>TIZEN</a>");
+ label.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
+ 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);
+
+ // Check that anchor color can be properly set
+ label.SetProperty(DevelTextLabel::Property::ANCHOR_COLOR, Color::BLUE);
+ DALI_TEST_EQUALS(label.GetProperty<Vector4>(DevelTextLabel::Property::ANCHOR_COLOR), Color::BLUE, TEST_LOCATION);
+
+ label.SetProperty(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR, Color::RED);
+ DALI_TEST_EQUALS(label.GetProperty<Vector4>(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR), Color::RED, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ // Create a tap event to touch the text label.
+ TestGenerateTap(application, 5.0f, 25.0f, 100);
+ application.SendNotification();
+ application.Render();
+
+ // Update clicked color
+ label.SetProperty(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR, Color::BLUE);
+ DALI_TEST_EQUALS(label.GetProperty<Vector4>(DevelTextLabel::Property::ANCHOR_CLICKED_COLOR), Color::BLUE, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(gAnchorClickedCallBackCalled);
+ DALI_TEST_CHECK(anchorClickedSignal);
+
+ END_TEST;
+}
+
// Positive test for the anchorClicked signal.
int UtcDaliToolkitTextlabelAnchorClicked(void)
{
* @note If the value is less than 1, the lines could to be overlapped.
*/
RELATIVE_LINE_SIZE,
+
+ /**
+ * @brief The anchor color that will be used by default in markup processing.
+ * @details Name "anchorColor", type Property::VECTOR4.
+ * @note If there is a color attribute in the anchor tag, the markup attribute takes precedence.
+ */
+ ANCHOR_COLOR,
+
+ /**
+ * @brief The anchor clicked color that will be used by default in markup processing.
+ * @details Name "anchorClickedColor", type Property::VECTOR4.
+ * @note If there is a color attribute in the anchor tag, the markup attribute takes precedence.
+ */
+ ANCHOR_CLICKED_COLOR,
};
} // namespace Property
if(textParameters.markupEnabled)
{
- ProcessMarkupString(textParameters.text, markupProcessData);
+ MarkupPropertyData markupPropertyData(Color::MEDIUM_BLUE, Color::DARK_MAGENTA);
+
+ ProcessMarkupString(textParameters.text, markupPropertyData, markupProcessData);
textSize = markupProcessData.markupProcessedText.size();
// This is a bit horrible but std::string returns a (signed) char*
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "strikethrough", MAP, STRIKETHROUGH )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "characterSpacing", FLOAT, CHARACTER_SPACING )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "relativeLineSize", FLOAT, RELATIVE_LINE_SIZE )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "anchorColor", VECTOR4, ANCHOR_COLOR )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "anchorClickedColor", VECTOR4, ANCHOR_CLICKED_COLOR )
DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0)
impl.mController->SetRelativeLineSize(relativeLineSize);
break;
}
+ case Toolkit::DevelTextLabel::Property::ANCHOR_COLOR:
+ {
+ const Vector4& anchorColor = value.Get<Vector4>();
+ if(impl.mController->GetAnchorColor() != anchorColor)
+ {
+ impl.mController->SetAnchorColor(anchorColor);
+ impl.mTextUpdateNeeded = true;
+ }
+ break;
+ }
+ case Toolkit::DevelTextLabel::Property::ANCHOR_CLICKED_COLOR:
+ {
+ const Vector4& anchorClickedColor = value.Get<Vector4>();
+ if(impl.mController->GetAnchorClickedColor() != anchorClickedColor)
+ {
+ impl.mController->SetAnchorClickedColor(anchorClickedColor);
+ impl.mTextUpdateNeeded = true;
+ }
+ break;
+ }
}
// Request relayout when text update is needed. It's necessary to call it
value = impl.mController->GetRelativeLineSize();
break;
}
+ case Toolkit::DevelTextLabel::Property::ANCHOR_COLOR:
+ {
+ value = impl.mController->GetAnchorColor();
+ break;
+ }
+ case Toolkit::DevelTextLabel::Property::ANCHOR_CLICKED_COLOR:
+ {
+ value = impl.mController->GetAnchorClickedColor();
+ break;
+ }
}
}
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.
+ uint32_t colorRunIndex; ///< RunIndex of color run, used to change color when property updated or clicked.
+ uint32_t underlinedCharacterRunIndex; ///< RunIndex of underline run, used to change color when property updated or clicked.
+
+ Vector4 markupClickedColor; ///< The markup color of the anchor when clicked. if there is no markup attribute, the default color stored in the controller is used.
+
+ bool isClicked = false; ///< Whether the anchor is clicked or not.
+ bool isMarkupColorSet = false; ///< Whether the markup color has been set or not.
+ bool isMarkupClickedColorSet = false; ///< Whether the markup clicked color has been set or not.
};
} // namespace Text
// TODO: in mutable text, the anchor color and underline run index should be able to be updated.
if(!controller.IsEditable())
{
+ // If there is a markup clicked color attribute, use it. Otherwise, use the property color.
if(controller.mImpl->mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
{
ColorRun& colorRun = *(controller.mImpl->mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
- colorRun.color = anchor.clickedColor;
+ colorRun.color = anchor.isMarkupClickedColorSet ? anchor.markupClickedColor : controller.mImpl->mAnchorClickedColor;
}
if(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
{
UnderlinedCharacterRun& underlineRun = *(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
- underlineRun.properties.color = anchor.clickedColor;
+ underlineRun.properties.color = anchor.isMarkupClickedColorSet ? anchor.markupClickedColor : controller.mImpl->mAnchorClickedColor;
}
controller.mImpl->ClearFontData();
return ControllerImplEventHandler::ProcessInputEvents(*this);
}
+void Controller::Impl::SetAnchorColor(const Vector4& color)
+{
+ mAnchorColor = color;
+ UpdateAnchorColor();
+}
+
+const Vector4& Controller::Impl::GetAnchorColor() const
+{
+ return mAnchorColor;
+}
+
+void Controller::Impl::SetAnchorClickedColor(const Vector4& color)
+{
+ mAnchorClickedColor = color;
+ UpdateAnchorColor();
+}
+
+const Vector4& Controller::Impl::GetAnchorClickedColor() const
+{
+ return mAnchorClickedColor;
+}
+
+void Controller::Impl::UpdateAnchorColor()
+{
+ if(!mAnchorControlInterface ||
+ !mMarkupProcessorEnabled ||
+ !mModel->mLogicalModel->mAnchors.Count() ||
+ !IsShowingRealText())
+ {
+ return;
+ }
+
+ bool updateNeeded = false;
+
+ // The anchor color & clicked color needs to be updated with the property's color.
+ for(auto& anchor : mModel->mLogicalModel->mAnchors)
+ {
+ if(!anchor.isMarkupColorSet && !anchor.isClicked)
+ {
+ if(mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
+ {
+ ColorRun& colorRun = *(mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
+ colorRun.color = mAnchorColor;
+ updateNeeded = true;
+ }
+ if(mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
+ {
+ UnderlinedCharacterRun& underlineRun = *(mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
+ underlineRun.properties.color = mAnchorColor;
+ updateNeeded = true;
+ }
+ }
+ else if(!anchor.isMarkupClickedColorSet && anchor.isClicked)
+ {
+ if(mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
+ {
+ ColorRun& colorRun = *(mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
+ colorRun.color = mAnchorClickedColor;
+ updateNeeded = true;
+ }
+ if(mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
+ {
+ UnderlinedCharacterRun& underlineRun = *(mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
+ underlineRun.properties.color = mAnchorClickedColor;
+ updateNeeded = true;
+ }
+ }
+ }
+
+ if(updateNeeded)
+ {
+ ClearFontData();
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | COLOR);
+ RequestRelayout();
+ }
+}
+
void Controller::Impl::NotifyInputMethodContext()
{
if(mEventData && mEventData->mInputMethodContext)
mModel->mLogicalModel->mColorRuns.Clear();
mModel->mLogicalModel->ClearFontDescriptionRuns();
mModel->mLogicalModel->ClearStrikethroughRuns();
+ mModel->mLogicalModel->ClearUnderlineRuns();
}
void Controller::Impl::ResetScrollPosition()
mMetrics(),
mModifyEvents(),
mTextColor(Color::BLACK),
+ mAnchorColor(Color::MEDIUM_BLUE),
+ mAnchorClickedColor(Color::DARK_MAGENTA),
mTextUpdateInfo(),
mOperationsPending(NO_OPERATION),
mMaximumNumberOfCharacters(50u),
return mFontSizeScaleEnabled ? mFontSizeScale : 1.0f;
}
+ /**
+ * @copydoc Controller::SetAnchorColor()
+ */
+ void SetAnchorColor(const Vector4& color);
+
+ /**
+ * @copydoc Controller::GetAnchorColor()
+ */
+ const Vector4& GetAnchorColor() const;
+
+ /**
+ * @copydoc Controller::SetAnchorClickedColor()
+ */
+ void SetAnchorClickedColor(const Vector4& color);
+
+ /**
+ * @copydoc Controller::GetAnchorClickedColor()
+ */
+ const Vector4& GetAnchorClickedColor() const;
+
+ /**
+ * @brief Updates the color of anchors.
+ */
+ void UpdateAnchorColor();
+
/**
* @brief Helper to notify InputMethodContext with surrounding text & cursor changes.
*/
Layout::Engine mLayoutEngine; ///< The layout engine.
Vector<ModifyEvent> mModifyEvents; ///< Temporary stores the text set until the next relayout.
Vector4 mTextColor; ///< The regular text color
+ Vector4 mAnchorColor; ///< The anchor color
+ Vector4 mAnchorClickedColor; ///< The anchor clicked color
TextUpdateInfo mTextUpdateInfo; ///< Info of the characters updated.
OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
const uint8_t* utf8 = NULL;
if(impl.mMarkupProcessorEnabled)
{
- ProcessMarkupString(text, markupProcessData);
+ MarkupPropertyData markupPropertyData(impl.mAnchorColor, impl.mAnchorClickedColor);
+
+ ProcessMarkupString(text, markupPropertyData, markupProcessData);
textSize = markupProcessData.markupProcessedText.size();
// This is a bit horrible but std::string returns a (signed) char*
return mImpl->mTextColor;
}
+void Controller::SetAnchorColor(const Vector4& color)
+{
+ mImpl->SetAnchorColor(color);
+}
+
+const Vector4& Controller::GetAnchorColor() const
+{
+ return mImpl->GetAnchorColor();
+}
+
+void Controller::SetAnchorClickedColor(const Vector4& color)
+{
+ mImpl->SetAnchorClickedColor(color);
+}
+
+const Vector4& Controller::GetAnchorClickedColor() const
+{
+ return mImpl->GetAnchorClickedColor();
+}
+
void Controller::SetDisabledColorOpacity(float opacity)
{
mImpl->mDisabledColorOpacity = opacity;
*/
const Vector4& GetDefaultColor() const;
+ /**
+ * @brief Sets the anchor's default color.
+ *
+ * @param color The anchor color.
+ */
+ void SetAnchorColor(const Vector4& color);
+
+ /**
+ * @brief Retrieves the anchor's default color.
+ *
+ * @return The anchor color.
+ */
+ const Vector4& GetAnchorColor() const;
+
+ /**
+ * @brief Sets the anchor's clicked color.
+ *
+ * @param color The anchor color.
+ */
+ void SetAnchorClickedColor(const Vector4& color);
+
+ /**
+ * @brief Retrieves the anchor's clicked color.
+ *
+ * @return The anchor color.
+ */
+ const Vector4& GetAnchorClickedColor() const;
+
/**
* @brief Sets the user interaction enabled.
*
mStrikethroughCharacterRuns.Clear();
}
+void LogicalModel::ClearUnderlineRuns()
+{
+ mUnderlinedCharacterRuns.Clear();
+}
+
void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex,
Length numberOfCharacters)
{
*/
void ClearStrikethroughRuns();
+ /**
+ * @brief Clears the underline runs.
+ */
+ void ClearUnderlineRuns();
+
// Paragraphs
/**
}
else if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
{
+ // The markup anchor color is set on the text and underline color runs.
+ // This takes precedence over the anchor color property of the text-label.
ProcessColor(attribute, colorRun);
ProcessColorAttribute(attribute, underlinedCharacterRun);
+ anchor.isMarkupColorSet = true;
}
else if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::CLICKED_COLOR, attribute.nameBuffer, attribute.nameLength))
{
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, anchor.clickedColor);
+ // The markup anchor clicked color is stored here.
+ // This is later used when the anchor's click event occurs.
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, anchor.markupClickedColor);
+ anchor.isMarkupClickedColorSet = true;
}
}
}
}
else if(EQUAL == character) // '='
{
- addToNameValue = false; // next read characters will be added to the value.
- SkipWhiteSpace(tagBuffer, tagEndBuffer);
+ if(isQuotationOpen)
+ {
+ ++valueLength;
+ }
+ else
+ {
+ addToNameValue = false; // next read characters will be added to the value.
+ SkipWhiteSpace(tagBuffer, tagEndBuffer);
+ }
}
else if(QUOTATION_MARK == character) // '\''
{
* @brief Processes anchor tag for the color-run & underline-run.
*
* @param[in,out] markupProcessData The markup process data
+ * @param[in] markupPropertyData The markup property 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
*/
void ProcessAnchorForRun(
MarkupProcessData& markupProcessData,
+ MarkupPropertyData& markupPropertyData,
const Tag& tag,
StyleStack<AnchorForStack>& anchorStack,
Vector<ColorRun>& colorRuns,
anchor.endIndex = 0u;
anchor.colorRunIndex = colorRunIndex;
anchor.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
+ anchor.markupClickedColor = markupPropertyData.anchorClickedColor;
// Create a new run.
ColorRun colorRun;
anchorForStack.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
// Init default color
- colorRun.color = Color::MEDIUM_BLUE;
- underlinedCharacterRun.properties.color = Color::MEDIUM_BLUE;
+ colorRun.color = markupPropertyData.anchorColor;
+ underlinedCharacterRun.properties.color = markupPropertyData.anchorColor;
underlinedCharacterRun.properties.colorDefined = true;
ProcessAnchorTag(tag, anchor, colorRun, underlinedCharacterRun);
} // namespace
-void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData)
+void ProcessMarkupString(const std::string& markupString, MarkupPropertyData& markupPropertyData, MarkupProcessData& markupProcessData)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str());
else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
{
ProcessAnchorForRun(markupProcessData,
+ markupPropertyData,
tag,
anchorStack,
markupProcessData.colorRuns,
std::string markupProcessedText; ///< The mark-up string.
};
+struct MarkupPropertyData
+{
+ MarkupPropertyData(Vector4 anchorColor,
+ Vector4 anchorClickedColor)
+ : anchorColor(anchorColor),
+ anchorClickedColor(anchorClickedColor)
+ {
+ }
+
+ Vector4 anchorColor; ///< The anchor color
+ Vector4 anchorClickedColor; ///< The anchor clicked color
+};
+
/**
* @brief Process the mark-up string.
*
* @param[in] markupString The mark-up string.
+ * @param[in] markupPropertyData The property data that will be used by default in markup processing.
* @param[out] markupProcessData The plain text and the style.
*/
-void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData);
+void ProcessMarkupString(const std::string& markupString, MarkupPropertyData& markupPropertyData, MarkupProcessData& markupProcessData);
} // namespace Text