X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Ftext-controls%2Ftext-label-impl.cpp;h=52f9c2918aaac601c5e8328d4f7f50d12111b41c;hp=76d0ee2067f8b8bafe71a2353f114a7892e2cc6c;hb=HEAD;hpb=fc4ebd23458e95ade416baeb1a8cf44bac9bca13 diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 76d0ee2..5af0fe1 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -76,12 +78,12 @@ const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] = 1.0f // VerticalAlignment::BOTTOM }; -const std::string TEXT_FIT_ENABLE_KEY("enable"); -const std::string TEXT_FIT_MIN_SIZE_KEY("minSize"); -const std::string TEXT_FIT_MAX_SIZE_KEY("maxSize"); -const std::string TEXT_FIT_STEP_SIZE_KEY("stepSize"); -const std::string TEXT_FIT_FONT_SIZE_KEY("fontSize"); -const std::string TEXT_FIT_FONT_SIZE_TYPE_KEY("fontSizeType"); +const char* TEXT_FIT_ENABLE_KEY("enable"); +const char* TEXT_FIT_MIN_SIZE_KEY("minSize"); +const char* TEXT_FIT_MAX_SIZE_KEY("maxSize"); +const char* TEXT_FIT_STEP_SIZE_KEY("stepSize"); +const char* TEXT_FIT_FONT_SIZE_KEY("fontSize"); +const char* TEXT_FIT_FONT_SIZE_TYPE_KEY("fontSizeType"); #if defined(DEBUG_ENABLED) Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); @@ -141,6 +143,11 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "ellipsisPosition 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_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeFrontInset", BOOLEAN, REMOVE_FRONT_INSET ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeBackInset", BOOLEAN, REMOVE_BACK_INSET ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "cutout", BOOLEAN, CUTOUT ) 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) @@ -206,6 +213,10 @@ void ParseTextFitProperty(Text::ControllerPtr& controller, const Property::Map* } controller->SetTextFitEnabled(enabled); + // The TextFit operation is performed based on the MinLineSize set in the TextLabel at the moment when the TextFit property is set. + // So, if you change the TextLabel's MinLineSize after setting the TextFit property, it does not affect the operation of TextFit. + // This may require a new LineSize item in TextFit. + controller->SetTextFitLineSize(controller->GetDefaultLineSize()); if(isMinSizeSet) { controller->SetTextFitMinSize(minSize, type); @@ -351,6 +362,7 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: { const bool enableAutoScroll = value.Get(); + impl.mLastAutoScrollEnabled = enableAutoScroll; // If request to auto scroll is the same as current state then do nothing. if(enableAutoScroll != impl.mController->IsAutoScrollEnabled()) { @@ -491,14 +503,26 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro } case Toolkit::DevelTextLabel::Property::TEXT_FIT: { + // If TextFitArray is enabled, this should be disabled. + if(impl.mController->IsTextFitArrayEnabled()) + { + impl.mController->SetDefaultLineSize(impl.mController->GetCurrentLineSize()); + impl.mController->SetTextFitArrayEnabled(false); + } + ParseTextFitProperty(impl.mController, value.GetMap()); impl.mController->SetTextFitChanged(true); break; } case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: { - const float lineSize = value.Get(); - impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded; + const float lineSize = value.Get(); + // If TextFitArray is enabled, do not update the default line size. + if(!impl.mController->IsTextFitArrayEnabled()) + { + impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded; + } + impl.mController->SetCurrentLineSize(lineSize); break; } case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE: @@ -550,6 +574,51 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro impl.mController->SetRelativeLineSize(relativeLineSize); break; } + case Toolkit::DevelTextLabel::Property::ANCHOR_COLOR: + { + const Vector4& anchorColor = value.Get(); + 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(); + if(impl.mController->GetAnchorClickedColor() != anchorClickedColor) + { + impl.mController->SetAnchorClickedColor(anchorClickedColor); + impl.mTextUpdateNeeded = true; + } + break; + } + case Toolkit::DevelTextLabel::Property::REMOVE_FRONT_INSET: + { + const bool remove = value.Get(); + impl.mController->SetRemoveFrontInset(remove); + break; + } + case Toolkit::DevelTextLabel::Property::REMOVE_BACK_INSET: + { + const bool remove = value.Get(); + impl.mController->SetRemoveBackInset(remove); + break; + } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + const bool cutout = value.Get(); + + impl.mController->SetTextCutout(cutout); + + // Property doesn't affect the layout, only Visual must be updated + TextVisual::EnableRendererUpdate(impl.mVisual); + + // No need to trigger full re-layout. Instead call UpdateRenderer() directly + TextVisual::UpdateRenderer(impl.mVisual); + break; + } } // Request relayout when text update is needed. It's necessary to call it @@ -780,7 +849,8 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index } case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: { - value = impl.mController->GetDefaultLineSize(); + // If TextFitArray is enabled, the stored value (MIN_LINE_SIZE set by the user) is retrun. + value = impl.mController->IsTextFitArrayEnabled() ? impl.mController->GetCurrentLineSize() : impl.mController->GetDefaultLineSize(); break; } case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE: @@ -813,6 +883,31 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index 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; + } + case Toolkit::DevelTextLabel::Property::REMOVE_FRONT_INSET: + { + value = impl.mController->IsRemoveFrontInset(); + break; + } + case Toolkit::DevelTextLabel::Property::REMOVE_BACK_INSET: + { + value = impl.mController->IsRemoveBackInset(); + break; + } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + value = impl.mController->IsTextCutout(); + break; + } } } @@ -869,7 +964,7 @@ void TextLabel::OnInitialize() propertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT); mVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap); - DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual); + DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual, DepthIndex::CONTENT); TextVisual::SetAnimatableTextColorProperty(mVisual, Toolkit::TextLabel::Property::TEXT_COLOR); @@ -893,6 +988,11 @@ void TextLabel::OnInitialize() self.LayoutDirectionChangedSignal().Connect(this, &TextLabel::OnLayoutDirectionChanged); + if(Dali::Adaptor::IsAvailable()) + { + Dali::Adaptor::Get().LocaleChangedSignal().Connect(this, &TextLabel::OnLocaleChanged); + } + Layout::Engine& engine = mController->GetLayoutEngine(); engine.SetCursorWidth(0u); // Do not layout space for the cursor. @@ -1000,6 +1100,49 @@ void TextLabel::OnPropertySet(Property::Index index, const Property::Value& prop CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors); break; } + case Toolkit::Control::Property::BACKGROUND: + { + const Vector4 backgroundColor = propertyValue.Get(); + + if(mController->IsTextCutout()) + { + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false); + mController->SetBackgroundWithCutoutEnabled(true); + mController->SetBackgroundColorWithCutout(backgroundColor); + } + + break; + } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + const bool cutoutEnabled = propertyValue.Get(); + + if(cutoutEnabled) + { + Vector4 backgroundColor = Vector4::ZERO; + + const Property::Map backgroundMap = Self().GetProperty(Toolkit::Control::Property::BACKGROUND).Get(); + Property::Value* backgroundValue = backgroundMap.Find(ColorVisual::Property::MIX_COLOR); + if(backgroundValue) + { + backgroundColor = backgroundValue->Get(); + } + + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false); + mController->SetBackgroundWithCutoutEnabled(true); + mController->SetBackgroundColorWithCutout(backgroundColor); + } + else + { + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, true); + + Property::Map backgroundMapSet; + mController->SetBackgroundWithCutoutEnabled(false); + } + + TextVisual::SetRequireRender(mVisual, cutoutEnabled); + break; + } default: { Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties @@ -1008,10 +1151,45 @@ void TextLabel::OnPropertySet(Property::Index index, const Property::Value& prop } } +void TextLabel::OnSceneConnection(int depth) +{ + if(mController->IsAutoScrollEnabled() || mLastAutoScrollEnabled) + { + mController->SetAutoScrollEnabled(true); + } + Control::OnSceneConnection(depth); +} + +void TextLabel::OnSceneDisconnection() +{ + if(mTextScroller) + { + if(mLastAutoScrollEnabled && !mController->IsAutoScrollEnabled()) + { + mLastAutoScrollEnabled = false; + } + + if(mTextScroller->IsScrolling()) + { + const Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = mTextScroller->GetStopMode(); + mTextScroller->SetStopMode(Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE); + mTextScroller->StopScrolling(); + mTextScroller->SetStopMode(stopMode); + } + } + Control::OnSceneDisconnection(); +} + void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container) { DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout\n"); + if(mTextScroller && mTextScroller->IsStop()) + { + // When auto scroll is playing, it triggers a relayout only when an update is absolutely necessary. + return; + } + Actor self = Self(); Extents padding; @@ -1019,7 +1197,12 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container) Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom)); - if(mController->IsTextFitEnabled()) + if(mController->IsTextFitArrayEnabled()) + { + mController->FitArrayPointSizeforLayout(contentSize); + mController->SetTextFitContentSize(contentSize); + } + else if(mController->IsTextFitEnabled()) { mController->FitPointSizeforLayout(contentSize); mController->SetTextFitContentSize(contentSize); @@ -1062,10 +1245,25 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container) alignmentOffset.x = 0.0f; alignmentOffset.y = (contentSize.y - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()]; + const int maxTextureSize = Dali::GetMaxTextureSize(); + if(layoutSize.width > maxTextureSize) + { + DALI_LOG_WARNING("layoutSize(%f) > maxTextureSize(%d): To guarantee the behavior of Texture::New, layoutSize must not be bigger than maxTextureSize\n", layoutSize.width, maxTextureSize); + layoutSize.width = maxTextureSize; + } + + // This affects font rendering quality. + // It need to be integerized. + Vector2 visualTransformOffset; + visualTransformOffset.x = roundf(padding.start + alignmentOffset.x); + visualTransformOffset.y = roundf(padding.top + alignmentOffset.y); + + mController->SetVisualTransformOffset(visualTransformOffset); + Property::Map visualTransform; visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, layoutSize) .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) - .Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2(padding.start, padding.top) + alignmentOffset) + .Add(Toolkit::Visual::Transform::Property::OFFSET, visualTransformOffset) .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN); @@ -1125,6 +1323,7 @@ void TextLabel::SetUpAutoScrolling() if(textNaturalSize.width > maxTextureSize) { mController->SetTextElideEnabled(true); + mController->SetAutoScrollMaxTextureExceeded(true); } GetHeightForWidth(maxTextureSize); wrapGap = std::max(maxTextureSize - textNaturalSize.width, 0.0f); @@ -1152,6 +1351,7 @@ void TextLabel::SetUpAutoScrolling() Renderer renderer = static_cast(GetImplementation(mVisual)).GetRenderer(); mTextScroller->SetParameters(Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment()); mController->SetTextElideEnabled(actualellipsis); + mController->SetAutoScrollMaxTextureExceeded(false); } void TextLabel::ScrollingFinished() @@ -1167,6 +1367,20 @@ void TextLabel::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type mController->ChangedLayoutDirection(); } +void TextLabel::OnLocaleChanged(std::string locale) +{ + if(mLocale != locale) + { + mLocale = locale; + mController->ResetFontAndStyleData(); + } +} + +std::string TextLabel::GetLocale() +{ + return mLocale; +} + void TextLabel::EmitTextFitChangedSignal() { Dali::Toolkit::TextLabel handle(GetOwner()); @@ -1178,10 +1392,12 @@ void TextLabel::OnAccessibilityStatusChanged() CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors); } -TextLabel::TextLabel(ControlBehaviour additionalBehavior) -: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehavior)), +TextLabel::TextLabel(ControlBehaviour additionalBehaviour) +: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour)), + mLocale(std::string()), mRenderingBackend(DEFAULT_RENDERING_BACKEND), - mTextUpdateNeeded(false) + mTextUpdateNeeded(false), + mLastAutoScrollEnabled(false) { } @@ -1199,6 +1415,72 @@ Vector TextLabel::GetTextPosition(const uint32_t startIndex, const uint return mController->GetTextPosition(startIndex, endIndex); } +Rect TextLabel::GetLineBoundingRectangle(const uint32_t lineIndex) const +{ + return mController->GetLineBoundingRectangle(lineIndex); +} + +Rect TextLabel::GetCharacterBoundingRectangle(const uint32_t charIndex) const +{ + return mController->GetCharacterBoundingRectangle(charIndex); +} + +int TextLabel::GetCharacterIndexAtPosition(float visualX, float visualY) const +{ + return mController->GetCharacterIndexAtPosition(visualX, visualY); +} + +Rect<> TextLabel::GetTextBoundingRectangle(uint32_t startIndex, uint32_t endIndex) const +{ + return mController->GetTextBoundingRectangle(startIndex, endIndex); +} + +void TextLabel::SetSpannedText(const Text::Spanned& spannedText) +{ + mController->SetSpannedText(spannedText); +} + +void TextLabel::SetTextFitArray(const bool enable, std::vector& fitOptions) +{ + if(!enable) + { + // If TextFitArray is disabled, MinLineSize shoud be restored to its original size. + mController->SetDefaultLineSize(mController->GetCurrentLineSize()); + } + mController->SetTextFitArrayEnabled(enable); + mController->SetTextFitArray(fitOptions); +} + +std::vector& TextLabel::GetTextFitArray() +{ + return mController->GetTextFitArray(); +} + +bool TextLabel::IsTextFitArrayEnabled() const +{ + return mController->IsTextFitArrayEnabled(); +} + +void TextLabel::SetRemoveFrontInset(bool remove) +{ + mController->SetRemoveFrontInset(remove); +} + +bool TextLabel::IsRemoveFrontInset() const +{ + return mController->IsRemoveFrontInset(); +} + +void TextLabel::SetRemoveBackInset(bool remove) +{ + mController->SetRemoveBackInset(remove); +} + +bool TextLabel::IsRemoveBackInset() const +{ + return mController->IsRemoveBackInset(); +} + std::string TextLabel::TextLabelAccessible::GetNameRaw() const { return GetWholeText();