From: Shinwoo Kim Date: Tue, 23 Nov 2021 07:31:42 +0000 (+0000) Subject: Merge "[ATSPI] do not send ROLE property changed event" into devel/master X-Git-Tag: dali_2.1.0~6 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=bad241077bd728d9a5ef25d59398eae889b359a1;hp=13a7c74fa789734b05d19d68bae51ac68e3b9713 Merge "[ATSPI] do not send ROLE property changed event" into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp index 6b77f00..eea6fa6 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -221,6 +222,20 @@ int utcDaliAccessibilityTextFieldGetText(void) DALI_TEST_EQUALS( x->GetText( 0, 0 ), "", TEST_LOCATION ); field.SetProperty( Toolkit::TextField::Property::TEXT, "exemplary_text" ); DALI_TEST_EQUALS( x->GetText( 0, 9 ), "exemplary", TEST_LOCATION ); + + Dali::Property::Map hiddenInputSettings; + hiddenInputSettings[ Toolkit::HiddenInput::Property::MODE ] = Toolkit::HiddenInput::Mode::HIDE_ALL; + + field.SetProperty( Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS, hiddenInputSettings ); + + DALI_TEST_EQUALS( x->GetName(), "", TEST_LOCATION ); + DALI_TEST_EQUALS( x->GetText( 0, 9 ), "*********", TEST_LOCATION ); + + hiddenInputSettings[ Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER ] = 0x23; + field.SetProperty( Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS, hiddenInputSettings ); + + DALI_TEST_EQUALS( x->GetName(), "", TEST_LOCATION ); + DALI_TEST_EQUALS( x->GetText( 0, 9 ), "#########", TEST_LOCATION ); } END_TEST; @@ -294,6 +309,16 @@ int utcDaliAccessibilityTextFieldGetTextAtOffset(void) DALI_TEST_EQUALS( range.content, " test sentence", TEST_LOCATION ); DALI_TEST_EQUALS( range.startOffset, 25, TEST_LOCATION ); DALI_TEST_EQUALS( range.endOffset, 39, TEST_LOCATION ); + + Dali::Property::Map hiddenInputSettings; + hiddenInputSettings[ Toolkit::HiddenInput::Property::MODE ] = Toolkit::HiddenInput::Mode::HIDE_ALL; + hiddenInputSettings[ Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER ] = 0x23; + field.SetProperty( Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS, hiddenInputSettings ); + range = x->GetTextAtOffset( 8, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + } END_TEST; @@ -321,6 +346,15 @@ int utcDaliAccessibilityTextFieldGetSetRangeOfSelection(void) DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); DALI_TEST_EQUALS( range.content, "plary", TEST_LOCATION ); + + Dali::Property::Map hiddenInputSettings; + hiddenInputSettings[ Toolkit::HiddenInput::Property::MODE ] = Toolkit::HiddenInput::Mode::HIDE_ALL; + field.SetProperty( Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS, hiddenInputSettings ); + + range = x->GetRangeOfSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "*****", TEST_LOCATION ); } END_TEST; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index be0e5b1..b0f9764 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -82,6 +82,8 @@ const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64 static bool gAnchorClickedCallBackCalled; static bool gAnchorClickedCallBackNotCalled; +static bool gTextFitChangedCallBackCalled; + struct CallbackFunctor { CallbackFunctor(bool* callbackFlag) @@ -108,6 +110,12 @@ static void TestAnchorClickedCallback(TextLabel control, const char* href, unsig } } +static void TestTextFitChangedCallback(TextLabel control) +{ + tet_infoline(" TestTextFitChangedCallback"); + gTextFitChangedCallBackCalled = true; +} + bool DaliTestCheckMaps( const Property::Map& mapGet, const Property::Map& mapSet, const std::vector& indexConversionTable = std::vector() ) { const Property::Map::SizeType size = mapGet.Count(); @@ -1663,6 +1671,13 @@ int UtcDaliToolkitTextlabelTextFit(void) label.SetProperty( Actor::Property::SIZE, size ); label.SetProperty( TextLabel::Property::TEXT, "Hello world" ); + // connect to the text git changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + DevelTextLabel::TextFitChangedSignal(label).Connect(&TestTextFitChangedCallback); + bool textFitChangedSignal = false; + label.ConnectSignal(testTracker, "textFitChanged", CallbackFunctor(&textFitChangedSignal)); + gTextFitChangedCallBackCalled = false; + // check point size Property::Map textFitMapSet; textFitMapSet["enable"] = true; @@ -1682,6 +1697,9 @@ int UtcDaliToolkitTextlabelTextFit(void) const Vector3 EXPECTED_NATURAL_SIZE( 450.0f, 96.0f, 0.0f ); DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION ); + DALI_TEST_CHECK(gTextFitChangedCallBackCalled); + DALI_TEST_CHECK(textFitChangedSignal); + // check pixel size textFitMapSet.Clear(); textFitMapSet["enable"] = true; @@ -2058,4 +2076,4 @@ int UtcDaliToolkitTextlabelEllipsisPositionProperty(void) END_TEST; -} \ No newline at end of file +} diff --git a/build/tizen/docs/dali.doxy.in b/build/tizen/docs/dali.doxy.in index 27a21bc..0fefc0e 100644 --- a/build/tizen/docs/dali.doxy.in +++ b/build/tizen/docs/dali.doxy.in @@ -357,6 +357,7 @@ ALIASES += SINCE_1_3="@since 1.3" ALIASES += SINCE_1_4="@since 1.4" ALIASES += SINCE_1_9="@since 1.9" ALIASES += SINCE_2_0="@since 2.0" +ALIASES += SINCE_2_1="@since 2.1" # Extra tags for Tizen 3.0 ALIASES += SINCE_1_2_2="@since 1.2.2" @@ -385,6 +386,7 @@ ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 1.3.39" ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 1.3.51" ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 1.4" ALIASES += DEPRECATED_2_0="@deprecated Deprecated since 2.0" +ALIASES += DEPRECATED_2_1="@deprecated Deprecated since 2.1" ALIASES += PLATFORM="" ALIASES += PRIVLEVEL_PLATFORM="" @@ -404,7 +406,8 @@ ALIASES += REMARK_RAWVIDEO="" #ALIASES += SINCE_1_3="\par Since:\n 5.0, DALi version 1.3" #ALIASES += SINCE_1_4="\par Since:\n 5.5, DALi version 1.4" #ALIASES += SINCE_1_9="\par Since:\n 6.0, DALi version 1.9" -#ALIASES += SINCE_2_0="\par Since:\n 6.0, DALi version 2.0" +#ALIASES += SINCE_2_0="\par Since:\n 6.5, DALi version 2.0" +#ALIASES += SINCE_2_1="\par Since:\n 7.0, DALi version 2.1" ## Extra tags for Tizen 3.0 #ALIASES += SINCE_1_2_2="\par Since:\n 3.0, DALi version 1.2.2" @@ -434,7 +437,8 @@ ALIASES += REMARK_RAWVIDEO="" #ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 5.5, DALi version 1.3.39" #ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 5.5, DALi version 1.3.51" #ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 5.5, DALi version 1.4" -#ALIASES += DEPRECATED_2_0="@deprecated Deprecated since 5.5, DALi version 2.0" +#ALIASES += DEPRECATED_2_0="@deprecated Deprecated since 6.5, DALi version 2.0" +#ALIASES += DEPRECATED_2_1="@deprecated Deprecated since 7.0, DALi version 2.1" #ALIASES += PLATFORM="@platform" #ALIASES += PRIVLEVEL_PLATFORM="\par Privilege Level:\n platform" diff --git a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.cpp b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.cpp index 0d6cd0b..c117152 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.cpp +++ b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.cpp @@ -30,6 +30,11 @@ AnchorClickedSignalType& AnchorClickedSignal(TextLabel textLabel) return GetImpl(textLabel).AnchorClickedSignal(); } +TextFitChangedSignalType& TextFitChangedSignal(TextLabel textLabel) +{ + return GetImpl(textLabel).TextFitChangedSignal(); +} + } // namespace DevelTextLabel } // namespace Toolkit diff --git a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h index ac0f30c..6bcbdd0 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h @@ -176,6 +176,11 @@ enum Type using AnchorClickedSignalType = Signal; /** + * @brief TextFit property changed signal type. + */ +using TextFitChangedSignalType = Signal; + +/** * @brief This signal is emitted when the anchor is clicked. * * A callback of the following type may be connected: @@ -187,6 +192,18 @@ using AnchorClickedSignalType = Signal; */ DALI_TOOLKIT_API AnchorClickedSignalType& AnchorClickedSignal(TextLabel textLabel); +/** + * @brief This signal is emitted when the textfit property is changed. + * + * A callback of the following type may be connected: + * @code + * void YourCallbackName(TextLabel textLabel); + * @endcode + * @param[in] textLabel The instance of TextLabel. + * @return The signal to connect to. + */ +DALI_TOOLKIT_API TextFitChangedSignalType& TextFitChangedSignal(TextLabel textLabel); + } // namespace DevelTextLabel } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp new file mode 100644 index 0000000..9c1272c --- /dev/null +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali::Toolkit::Internal +{ + +void ScrollViewPropertyHandler::Set(BaseObject* object, Property::Index index, const Property::Value& value) +{ + Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object)); + + if(scrollView) + { + ScrollView& scrollViewImpl(GetImpl(scrollView)); + switch(index) + { + case Toolkit::ScrollView::Property::WRAP_ENABLED: + { + scrollViewImpl.SetWrapMode(value.Get()); + break; + } + case Toolkit::ScrollView::Property::PANNING_ENABLED: + { + scrollViewImpl.SetScrollSensitive(value.Get()); + break; + } + case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED: + { + scrollViewImpl.SetAxisAutoLock(value.Get()); + break; + } + case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP: + { + scrollViewImpl.SetWheelScrollDistanceStep(value.Get()); + break; + } + case Toolkit::ScrollView::Property::SCROLL_MODE: + { + const Property::Map* map = value.GetMap(); + if(map) + { + SetScrollMode(scrollViewImpl, *map); + } + } + } + } +} + +Property::Value ScrollViewPropertyHandler::Get(BaseObject* object, Property::Index index) +{ + Property::Value value; + + Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object)); + + if(scrollView) + { + ScrollView& scrollViewImpl(GetImpl(scrollView)); + switch(index) + { + case Toolkit::ScrollView::Property::WRAP_ENABLED: + { + value = scrollViewImpl.GetWrapMode(); + break; + } + case Toolkit::ScrollView::Property::PANNING_ENABLED: + { + value = scrollViewImpl.GetScrollSensitive(); + break; + } + case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED: + { + value = scrollViewImpl.GetAxisAutoLock(); + break; + } + case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP: + { + value = scrollViewImpl.GetWheelScrollDistanceStep(); + break; + } + } + } + + return value; +} + +void ScrollViewPropertyHandler::SetScrollMode(ScrollView& scrollView, const Property::Map& scrollModeMap) +{ + Toolkit::RulerPtr rulerX, rulerY; + + // Check the scroll mode in the X axis + bool xAxisScrollEnabled = true; + Property::Value* valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_ENABLED, "xAxisScrollEnabled"); + if(valuePtr && valuePtr->GetType() == Property::BOOLEAN) + { + valuePtr->Get(xAxisScrollEnabled); + } + + if(!xAxisScrollEnabled) + { + // Default ruler and disabled + rulerX = new Toolkit::DefaultRuler(); + rulerX->Disable(); + } + else + { + valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SNAP_TO_INTERVAL, "xAxisSnapToInterval"); + float xAxisSnapToInterval = 0.0f; + if(valuePtr && valuePtr->Get(xAxisSnapToInterval)) + { + // Fixed ruler and enabled + rulerX = new Toolkit::FixedRuler(xAxisSnapToInterval); + } + else + { + // Default ruler and enabled + rulerX = new Toolkit::DefaultRuler(); + } + + valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_BOUNDARY, "xAxisScrollBoundary"); + float xAxisScrollBoundary = 0.0f; + if(valuePtr && valuePtr->Get(xAxisScrollBoundary)) + { + // By default ruler domain is disabled unless set + rulerX->SetDomain(Toolkit::RulerDomain(0, xAxisScrollBoundary, true)); + } + } + + // Check the scroll mode in the Y axis + bool yAxisScrollEnabled = true; + valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_ENABLED, "yAxisScrollEnabled"); + if(valuePtr && valuePtr->GetType() == Property::BOOLEAN) + { + valuePtr->Get(yAxisScrollEnabled); + } + + if(!yAxisScrollEnabled) + { + // Default ruler and disabled + rulerY = new Toolkit::DefaultRuler(); + rulerY->Disable(); + } + else + { + valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, "yAxisSnapToInterval"); + float yAxisSnapToInterval = 0.0f; + if(valuePtr && valuePtr->Get(yAxisSnapToInterval)) + { + // Fixed ruler and enabled + rulerY = new Toolkit::FixedRuler(yAxisSnapToInterval); + } + else + { + // Default ruler and enabled + rulerY = new Toolkit::DefaultRuler(); + } + + valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_BOUNDARY, "yAxisScrollBoundary"); + float yAxisScrollBoundary = 0.0f; + if(valuePtr && valuePtr->Get(yAxisScrollBoundary)) + { + // By default ruler domain is disabled unless set + rulerY->SetDomain(Toolkit::RulerDomain(0, yAxisScrollBoundary, true)); + } + } + + scrollView.SetRulerX(rulerX); + scrollView.SetRulerY(rulerY); +} + +void ScrollViewPropertyHandler::UpdatePropertyDomain(ScrollView& scrollView) +{ + Actor self = scrollView.Self(); + Vector3 size = self.GetTargetSize(); + Vector2 min = scrollView.mMinScroll; + Vector2 max = scrollView.mMaxScroll; + bool scrollPositionChanged = false; + bool domainChanged = false; + + bool canScrollVertical = false; + bool canScrollHorizontal = false; + scrollView.UpdateLocalScrollProperties(); + if(scrollView.mRulerX->IsEnabled()) + { + const Toolkit::RulerDomain& rulerDomain = scrollView.mRulerX->GetDomain(); + if(fabsf(min.x - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.x - rulerDomain.max) > Math::MACHINE_EPSILON_100) + { + domainChanged = true; + min.x = rulerDomain.min; + max.x = rulerDomain.max; + + // make sure new scroll value is within new domain + if(scrollView.mScrollPrePosition.x < min.x || scrollView.mScrollPrePosition.x > max.x) + { + scrollPositionChanged = true; + scrollView.mScrollPrePosition.x = Clamp(scrollView.mScrollPrePosition.x, -(max.x - size.x), -min.x); + } + } + if((fabsf(rulerDomain.max - rulerDomain.min) - size.x) > Math::MACHINE_EPSILON_100) + { + canScrollHorizontal = true; + } + } + else if(fabs(min.x) > Math::MACHINE_EPSILON_100 || fabs(max.x) > Math::MACHINE_EPSILON_100) + { + // need to reset to 0 + domainChanged = true; + min.x = 0.0f; + max.x = 0.0f; + canScrollHorizontal = false; + } + + if(scrollView.mRulerY->IsEnabled()) + { + const Toolkit::RulerDomain& rulerDomain = scrollView.mRulerY->GetDomain(); + if(fabsf(min.y - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.y - rulerDomain.max) > Math::MACHINE_EPSILON_100) + { + domainChanged = true; + min.y = rulerDomain.min; + max.y = rulerDomain.max; + + // make sure new scroll value is within new domain + if(scrollView.mScrollPrePosition.y < min.y || scrollView.mScrollPrePosition.y > max.y) + { + scrollPositionChanged = true; + scrollView.mScrollPrePosition.y = Clamp(scrollView.mScrollPrePosition.y, -(max.y - size.y), -min.y); + } + } + if((fabsf(rulerDomain.max - rulerDomain.min) - size.y) > Math::MACHINE_EPSILON_100) + { + canScrollVertical = true; + } + } + else if(fabs(min.y) > Math::MACHINE_EPSILON_100 || fabs(max.y) > Math::MACHINE_EPSILON_100) + { + // need to reset to 0 + domainChanged = true; + min.y = 0.0f; + max.y = 0.0f; + canScrollVertical = false; + } + + // avoid setting properties if possible, otherwise this will cause an entire update as well as triggering constraints using each property we update + if(scrollView.mCanScrollVertical != canScrollVertical) + { + scrollView.mCanScrollVertical = canScrollVertical; + self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, canScrollVertical); + } + if(scrollView.mCanScrollHorizontal != canScrollHorizontal) + { + scrollView.mCanScrollHorizontal = canScrollHorizontal; + self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, canScrollHorizontal); + } + if(scrollPositionChanged) + { + self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, scrollView.mScrollPrePosition); + } + if(domainChanged) + { + scrollView.mMinScroll = min; + scrollView.mMaxScroll = max; + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, scrollView.mMinScroll); + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, scrollView.mMaxScroll); + } +} + +} // namespace Dali::Toolkit::Internal diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h new file mode 100644 index 0000000..1923cfc --- /dev/null +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h @@ -0,0 +1,69 @@ +#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H +#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H + +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include + +namespace Dali::Toolkit::Internal +{ +class ScrollView; + +/// Handles the properties in scroll view calling the appropriate scroll view methods +struct ScrollViewPropertyHandler +{ + /** + * @brief Sets the property on the given scroll-view object. + * + * @param object The scrollview object + * @param index The index to set + * @param value The value to set + */ + static void Set(BaseObject* object, Property::Index index, const Property::Value& value); + + /** + * @brief Retrieves the value of a scroll-view property. + * + * @param object The scrollview object + * @param index The index whose value is to be retrieved + * @return + */ + static Property::Value Get(BaseObject* object, Property::Index index); + + /** + * Set up default rulers using a property map + * @param[in] scrollView The scroll view to apply this on + * @param[in] scrollModeMap A map defining the characteristics of X and Y scrolling + * using either FixedRuler or DefaultRuler. + */ + static void SetScrollMode(ScrollView& scrollView, const Property::Map& scrollModeMap); + + /** + * This is called whenever the Scroll Rulers are modified. + * + * This will update the properties: 'scrollPositionMin' * and 'scrollPositionMax' to reflect the changes. + * @param scrollView The Scroll View to modify + */ + static void UpdatePropertyDomain(ScrollView& scrollView); +}; + +} // namespace Dali::Toolkit::Internal + +#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp index 86cfc56..712cb17 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -673,7 +674,7 @@ void ScrollView::OnInitialize() self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, mCanScrollVertical); self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal); - UpdatePropertyDomain(); + ScrollViewPropertyHandler::UpdatePropertyDomain(*this); mConstraints.SetInternalConstraints(*this); // Connect wheel event @@ -794,7 +795,7 @@ void ScrollView::SetRulerX(RulerPtr ruler) { mRulerX = ruler; - UpdatePropertyDomain(); + ScrollViewPropertyHandler::UpdatePropertyDomain(*this); mConstraints.UpdateMainInternalConstraint(*this); } @@ -802,107 +803,10 @@ void ScrollView::SetRulerY(RulerPtr ruler) { mRulerY = ruler; - UpdatePropertyDomain(); + ScrollViewPropertyHandler::UpdatePropertyDomain(*this); mConstraints.UpdateMainInternalConstraint(*this); } -void ScrollView::UpdatePropertyDomain() -{ - Actor self = Self(); - Vector3 size = self.GetTargetSize(); - Vector2 min = mMinScroll; - Vector2 max = mMaxScroll; - bool scrollPositionChanged = false; - bool domainChanged = false; - - bool canScrollVertical = false; - bool canScrollHorizontal = false; - UpdateLocalScrollProperties(); - if(mRulerX->IsEnabled()) - { - const Toolkit::RulerDomain& rulerDomain = mRulerX->GetDomain(); - if(fabsf(min.x - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.x - rulerDomain.max) > Math::MACHINE_EPSILON_100) - { - domainChanged = true; - min.x = rulerDomain.min; - max.x = rulerDomain.max; - - // make sure new scroll value is within new domain - if(mScrollPrePosition.x < min.x || mScrollPrePosition.x > max.x) - { - scrollPositionChanged = true; - mScrollPrePosition.x = Clamp(mScrollPrePosition.x, -(max.x - size.x), -min.x); - } - } - if((fabsf(rulerDomain.max - rulerDomain.min) - size.x) > Math::MACHINE_EPSILON_100) - { - canScrollHorizontal = true; - } - } - else if(fabs(min.x) > Math::MACHINE_EPSILON_100 || fabs(max.x) > Math::MACHINE_EPSILON_100) - { - // need to reset to 0 - domainChanged = true; - min.x = 0.0f; - max.x = 0.0f; - canScrollHorizontal = false; - } - - if(mRulerY->IsEnabled()) - { - const Toolkit::RulerDomain& rulerDomain = mRulerY->GetDomain(); - if(fabsf(min.y - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.y - rulerDomain.max) > Math::MACHINE_EPSILON_100) - { - domainChanged = true; - min.y = rulerDomain.min; - max.y = rulerDomain.max; - - // make sure new scroll value is within new domain - if(mScrollPrePosition.y < min.y || mScrollPrePosition.y > max.y) - { - scrollPositionChanged = true; - mScrollPrePosition.y = Clamp(mScrollPrePosition.y, -(max.y - size.y), -min.y); - } - } - if((fabsf(rulerDomain.max - rulerDomain.min) - size.y) > Math::MACHINE_EPSILON_100) - { - canScrollVertical = true; - } - } - else if(fabs(min.y) > Math::MACHINE_EPSILON_100 || fabs(max.y) > Math::MACHINE_EPSILON_100) - { - // need to reset to 0 - domainChanged = true; - min.y = 0.0f; - max.y = 0.0f; - canScrollVertical = false; - } - - // avoid setting properties if possible, otherwise this will cause an entire update as well as triggering constraints using each property we update - if(mCanScrollVertical != canScrollVertical) - { - mCanScrollVertical = canScrollVertical; - self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, canScrollVertical); - } - if(mCanScrollHorizontal != canScrollHorizontal) - { - mCanScrollHorizontal = canScrollHorizontal; - self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, canScrollHorizontal); - } - if(scrollPositionChanged) - { - DALI_LOG_SCROLL_STATE("[0x%X] Domain Changed, setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y); - self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition); - } - if(domainChanged) - { - mMinScroll = min; - mMaxScroll = max; - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, mMinScroll); - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, mMaxScroll); - } -} - void ScrollView::SetScrollSensitive(bool sensitive) { Actor self = Self(); @@ -1482,7 +1386,7 @@ bool ScrollView::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize) { // need to update domain properties for new size - UpdatePropertyDomain(); + ScrollViewPropertyHandler::UpdatePropertyDomain(*this); } void ScrollView::OnSizeSet(const Vector3& size) @@ -1497,7 +1401,7 @@ void ScrollView::OnSizeSet(const Vector3& size) mMaxOvershoot = mUserMaxOvershoot; } } - UpdatePropertyDomain(); + ScrollViewPropertyHandler::UpdatePropertyDomain(*this); mConstraints.UpdateMainInternalConstraint(*this); if(IsOvershootEnabled()) { @@ -2180,45 +2084,6 @@ void ScrollView::FinishTransform() } } -Vector2 ScrollView::GetOvershoot(Vector2& position) const -{ - Vector3 size = Self().GetCurrentProperty(Actor::Property::SIZE); - Vector2 overshoot; - - const RulerDomain rulerDomainX = mRulerX->GetDomain(); - const RulerDomain rulerDomainY = mRulerY->GetDomain(); - - if(mRulerX->IsEnabled() && rulerDomainX.enabled) - { - const float left = rulerDomainX.min - position.x; - const float right = size.width - rulerDomainX.max - position.x; - if(left < 0) - { - overshoot.x = left; - } - else if(right > 0) - { - overshoot.x = right; - } - } - - if(mRulerY->IsEnabled() && rulerDomainY.enabled) - { - const float top = rulerDomainY.min - position.y; - const float bottom = size.height - rulerDomainY.max - position.y; - if(top < 0) - { - overshoot.y = top; - } - else if(bottom > 0) - { - overshoot.y = bottom; - } - } - - return overshoot; -} - bool ScrollView::OnAccessibilityPan(PanGesture gesture) { // Keep track of whether this is an AccessibilityPan @@ -2263,164 +2128,12 @@ void ScrollView::WrapPosition(Vector2& position) const void ScrollView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) { - Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object)); - - if(scrollView) - { - ScrollView& scrollViewImpl(GetImpl(scrollView)); - switch(index) - { - case Toolkit::ScrollView::Property::WRAP_ENABLED: - { - scrollViewImpl.SetWrapMode(value.Get()); - break; - } - case Toolkit::ScrollView::Property::PANNING_ENABLED: - { - scrollViewImpl.SetScrollSensitive(value.Get()); - break; - } - case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED: - { - scrollViewImpl.SetAxisAutoLock(value.Get()); - break; - } - case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP: - { - scrollViewImpl.SetWheelScrollDistanceStep(value.Get()); - break; - } - case Toolkit::ScrollView::Property::SCROLL_MODE: - { - const Property::Map* map = value.GetMap(); - if(map) - { - scrollViewImpl.SetScrollMode(*map); - } - } - } - } + ScrollViewPropertyHandler::Set(object, index, value); } Property::Value ScrollView::GetProperty(BaseObject* object, Property::Index index) { - Property::Value value; - - Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object)); - - if(scrollView) - { - ScrollView& scrollViewImpl(GetImpl(scrollView)); - switch(index) - { - case Toolkit::ScrollView::Property::WRAP_ENABLED: - { - value = scrollViewImpl.GetWrapMode(); - break; - } - case Toolkit::ScrollView::Property::PANNING_ENABLED: - { - value = scrollViewImpl.GetScrollSensitive(); - break; - } - case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED: - { - value = scrollViewImpl.GetAxisAutoLock(); - break; - } - case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP: - { - value = scrollViewImpl.GetWheelScrollDistanceStep(); - break; - } - } - } - - return value; -} - -void ScrollView::SetScrollMode(const Property::Map& scrollModeMap) -{ - Toolkit::RulerPtr rulerX, rulerY; - - // Check the scroll mode in the X axis - bool xAxisScrollEnabled = true; - Property::Value* valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_ENABLED, "xAxisScrollEnabled"); - if(valuePtr && valuePtr->GetType() == Property::BOOLEAN) - { - valuePtr->Get(xAxisScrollEnabled); - } - - if(!xAxisScrollEnabled) - { - // Default ruler and disabled - rulerX = new Toolkit::DefaultRuler(); - rulerX->Disable(); - } - else - { - valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SNAP_TO_INTERVAL, "xAxisSnapToInterval"); - float xAxisSnapToInterval = 0.0f; - if(valuePtr && valuePtr->Get(xAxisSnapToInterval)) - { - // Fixed ruler and enabled - rulerX = new Toolkit::FixedRuler(xAxisSnapToInterval); - } - else - { - // Default ruler and enabled - rulerX = new Toolkit::DefaultRuler(); - } - - valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_BOUNDARY, "xAxisScrollBoundary"); - float xAxisScrollBoundary = 0.0f; - if(valuePtr && valuePtr->Get(xAxisScrollBoundary)) - { - // By default ruler domain is disabled unless set - rulerX->SetDomain(Toolkit::RulerDomain(0, xAxisScrollBoundary, true)); - } - } - - // Check the scroll mode in the Y axis - bool yAxisScrollEnabled = true; - valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_ENABLED, "yAxisScrollEnabled"); - if(valuePtr && valuePtr->GetType() == Property::BOOLEAN) - { - valuePtr->Get(yAxisScrollEnabled); - } - - if(!yAxisScrollEnabled) - { - // Default ruler and disabled - rulerY = new Toolkit::DefaultRuler(); - rulerY->Disable(); - } - else - { - valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, "yAxisSnapToInterval"); - float yAxisSnapToInterval = 0.0f; - if(valuePtr && valuePtr->Get(yAxisSnapToInterval)) - { - // Fixed ruler and enabled - rulerY = new Toolkit::FixedRuler(yAxisSnapToInterval); - } - else - { - // Default ruler and enabled - rulerY = new Toolkit::DefaultRuler(); - } - - valuePtr = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_BOUNDARY, "yAxisScrollBoundary"); - float yAxisScrollBoundary = 0.0f; - if(valuePtr && valuePtr->Get(yAxisScrollBoundary)) - { - // By default ruler domain is disabled unless set - rulerY->SetDomain(Toolkit::RulerDomain(0, yAxisScrollBoundary, true)); - } - } - - SetRulerX(rulerX); - SetRulerY(rulerY); + return ScrollViewPropertyHandler::Get(object, index); } ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient) diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h index 4d871a7..4061727 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h @@ -47,6 +47,8 @@ typedef IntrusivePtr ScrollInternalConstraintsPtr; class ScrollOvershootIndicator; typedef IntrusivePtr ScrollOvershootIndicatorPtr; +class ScrollViewPropertyHandler; + /** * @copydoc Toolkit::ScrollView */ @@ -774,13 +776,6 @@ private: void SnapInternalYTo(float position); /** - * This is called internally whenever the Scroll Rulers are - * modified. This will update the properties: 'scrollPositionMin' - * and 'scrollPositionMax' to reflect the changes. - */ - void UpdatePropertyDomain(); - - /** * Called when the gesture starts. */ void GestureStarted(); @@ -821,20 +816,6 @@ private: void FinishTransform(); /** - * Returns overshoot vector based on current position - * - * Overshoot vector is defined as how far outside of bounds - * the viewport is trying to view (prior to being clamped). - * - * an overshoot of (100,50), means user is in bottom right corner, - * trying to pan +100 to the right, and +50 below. This can be used - * to determine an effect, such as stretching. - * - * @param[in] position The position for which you wish to obtain overshoot vector - */ - Vector2 GetOvershoot(Vector2& position) const; - - /** * Clamps position within the domain set up by X/Y Rulers * * @param[in,out] position The position you wish to clamp @@ -924,13 +905,6 @@ private: */ void OnScrollUpdateNotification(Dali::PropertyNotification& source); - /** - * Set up default rulers using a property map - * @param[in] scrollModeMap A map defining the characteristics of X and Y scrolling - * using either FixedRuler or DefaultRuler. - */ - void SetScrollMode(const Property::Map& scrollModeMap); - private: // Undefined ScrollView(const ScrollView&); @@ -1020,6 +994,7 @@ private: bool mTransientScrollBar : 1; ///< True if scroll-bar should be automatically show/hidden during/after panning friend ScrollViewConstraints; + friend ScrollViewPropertyHandler; }; /** diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index fe01e46..b48faa0 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -201,6 +201,28 @@ Toolkit::TextField::InputStyle::Mask ConvertInputStyle(Text::InputStyle::Mask in return fieldInputStyleMask; } +bool IsHiddenInput(Toolkit::TextField textField) +{ + Property::Map hiddenInputSettings = textField.GetProperty(Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS); + auto mode = hiddenInputSettings.Find(Toolkit::HiddenInput::Property::MODE); + if (mode && (mode->Get() != Toolkit::HiddenInput::Mode::HIDE_NONE)) + { + return true; + } + return false; +} + +char GetSubstituteCharacter(Toolkit::TextField textField) +{ + Property::Map hiddenInputSettings = textField.GetProperty(Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS); + auto substChar = hiddenInputSettings.Find(Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER); + if (substChar) + { + return static_cast(substChar->Get()); + } + return STAR; +} + } // namespace Toolkit::TextField TextField::New() @@ -1101,6 +1123,11 @@ TextField::~TextField() std::string TextField::AccessibleImpl::GetName() { auto self = Toolkit::TextField::DownCast(Self()); + if (IsHiddenInput(self)) + { + return {}; + } + return self.GetProperty(Toolkit::TextField::Property::TEXT).Get(); } @@ -1118,7 +1145,10 @@ std::string TextField::AccessibleImpl::GetText(size_t startOffset, size_t endOff { return {}; } - + if(IsHiddenInput(self)) + { + return std::string(endOffset - startOffset, GetSubstituteCharacter(self)); + } return text.substr(startOffset, endOffset - startOffset); } @@ -1156,11 +1186,18 @@ Dali::Accessibility::Range TextField::AccessibleImpl::GetTextAtOffset( size_t offset, Dali::Accessibility::TextBoundary boundary) { auto self = Toolkit::TextField::DownCast(Self()); + auto range = Dali::Accessibility::Range{}; + + if(IsHiddenInput(self)) + { + // Returning empty object, as there is no possibility to parse the textfield + // when its content is hidden. + return range; + } + auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get(); auto textSize = text.size(); - auto range = Dali::Accessibility::Range{}; - switch(boundary) { case Dali::Accessibility::TextBoundary::CHARACTER: @@ -1252,13 +1289,21 @@ Dali::Accessibility::Range TextField::AccessibleImpl::GetRangeOfSelection(size_t return {}; } - auto self = Toolkit::TextField::DownCast(Self()); - auto controller = Dali::Toolkit::GetImpl(self).GetTextController(); - std::string value{}; - controller->RetrieveSelection(value); + auto self = Toolkit::TextField::DownCast(Self()); + auto controller = Dali::Toolkit::GetImpl(self).GetTextController(); auto indices = controller->GetSelectionIndexes(); - return {static_cast(indices.first), static_cast(indices.second), value}; + auto startOffset = static_cast(indices.first); + auto endOffset = static_cast(indices.second); + + if (IsHiddenInput(self)) + { + return {startOffset, endOffset, std::string(endOffset - startOffset, GetSubstituteCharacter(self))}; + } + + std::string value{}; + controller->RetrieveSelection(value); + return {startOffset, endOffset, value}; } bool TextField::AccessibleImpl::RemoveSelection(size_t selectionIndex) diff --git a/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp b/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp index 04a5082..db08d3ae 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp @@ -507,6 +507,15 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope if(map) { impl.mController->SetHiddenInputOption(*map); + auto mode = map->Find(Toolkit::HiddenInput::Property::MODE); + if(mode && (mode->Get() != Toolkit::HiddenInput::Mode::HIDE_NONE)) + { + textField.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Accessibility::Role::PASSWORD_TEXT); + } + else + { + textField.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Accessibility::Role::ENTRY); + } } break; } 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 21e13c8..a98ef9b 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -79,6 +79,7 @@ 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"); #if defined(DEBUG_ENABLED) @@ -143,6 +144,7 @@ DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColo DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3) DALI_SIGNAL_REGISTRATION(Toolkit, TextLabel, "anchorClicked", SIGNAL_ANCHOR_CLICKED) +DALI_SIGNAL_REGISTRATION(Toolkit, TextLabel, "textFitChanged", SIGNAL_TEXT_FIT_CHANGED) DALI_TYPE_REGISTRATION_END() // clang-format on @@ -485,6 +487,7 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro case Toolkit::DevelTextLabel::Property::TEXT_FIT: { ParseTextFitProperty(impl.mController, value.GetMap()); + impl.mController->SetTextFitChanged(true); break; } case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: @@ -729,12 +732,14 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index const float minSize = impl.mController->GetTextFitMinSize(); const float maxSize = impl.mController->GetTextFitMaxSize(); const float stepSize = impl.mController->GetTextFitStepSize(); + const float pointSize = impl.mController->GetTextFitPointSize(); Property::Map map; map.Insert(TEXT_FIT_ENABLE_KEY, enabled); map.Insert(TEXT_FIT_MIN_SIZE_KEY, minSize); map.Insert(TEXT_FIT_MAX_SIZE_KEY, maxSize); map.Insert(TEXT_FIT_STEP_SIZE_KEY, stepSize); + map.Insert(TEXT_FIT_FONT_SIZE_KEY, pointSize); map.Insert(TEXT_FIT_FONT_SIZE_TYPE_KEY, "pointSize"); value = map; @@ -776,6 +781,14 @@ bool TextLabel::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* labelImpl.AnchorClickedSignal().Connect(tracker, functor); } } + else if(0 == strcmp(signalName.c_str(), SIGNAL_TEXT_FIT_CHANGED)) + { + if(label) + { + Internal::TextLabel& labelImpl(GetImpl(label)); + labelImpl.TextFitChangedSignal().Connect(tracker, functor); + } + } else { // signalName does not match any signal @@ -790,6 +803,11 @@ DevelTextLabel::AnchorClickedSignalType& TextLabel::AnchorClickedSignal() return mAnchorClickedSignal; } +DevelTextLabel::TextFitChangedSignalType& TextLabel::TextFitChangedSignal() +{ + return mTextFitChangedSignal; +} + void TextLabel::OnInitialize() { Actor self = Self(); @@ -997,6 +1015,12 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container) mTextUpdateNeeded = false; } + + if(mController->IsTextFitChanged()) + { + EmitTextFitChangedSignal(); + mController->SetTextFitChanged(false); + } } void TextLabel::RequestTextRelayout() @@ -1080,6 +1104,12 @@ void TextLabel::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type mController->ChangedLayoutDirection(); } +void TextLabel::EmitTextFitChangedSignal() +{ + Dali::Toolkit::TextLabel handle(GetOwner()); + mTextFitChangedSignal.Emit(handle); +} + TextLabel::TextLabel() : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)), mRenderingBackend(DEFAULT_RENDERING_BACKEND), diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/dali-toolkit/internal/controls/text-controls/text-label-impl.h index 01e003b..d345d21 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.h @@ -76,6 +76,11 @@ public: DevelTextLabel::AnchorClickedSignalType& AnchorClickedSignal(); /** + * @copydoc Dali::Toollkit::TextLabel::TextFitChangedSignal() + */ + DevelTextLabel::TextFitChangedSignalType& TextFitChangedSignal(); + + /** * Connects a callback function with the object's signals. * @param[in] object The object providing the signal. * @param[in] tracker Used to disconnect the signal. @@ -189,6 +194,11 @@ private: */ void OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type); + /** + * @brief Emits TextFitChanged signal. + */ + void EmitTextFitChangedSignal(); + private: // Data Text::ControllerPtr mController; Text::TextScrollerPtr mTextScroller; @@ -197,6 +207,7 @@ private: // Data // Signals Toolkit::DevelTextLabel::AnchorClickedSignalType mAnchorClickedSignal; + Toolkit::DevelTextLabel::TextFitChangedSignalType mTextFitChangedSignal; int mRenderingBackend; bool mTextUpdateNeeded : 1; diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 591915d..855df54 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -93,6 +93,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp + ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp ${toolkit_src_dir}/controls/scene3d-view/scene3d-view-impl.cpp ${toolkit_src_dir}/controls/scene3d-view/gltf-loader.cpp @@ -158,6 +159,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/text/text-controller.cpp ${toolkit_src_dir}/text/text-controller-event-handler.cpp ${toolkit_src_dir}/text/text-controller-impl.cpp + ${toolkit_src_dir}/text/text-controller-impl-data-clearer.cpp ${toolkit_src_dir}/text/text-controller-impl-event-handler.cpp ${toolkit_src_dir}/text/text-controller-impl-model-updater.cpp ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp diff --git a/dali-toolkit/internal/text/hidden-text.cpp b/dali-toolkit/internal/text/hidden-text.cpp index 1adbe83..ab2aba5 100644 --- a/dali-toolkit/internal/text/hidden-text.cpp +++ b/dali-toolkit/internal/text/hidden-text.cpp @@ -23,7 +23,6 @@ using namespace Dali::Toolkit; -const uint32_t STAR = 0x2A; // Set default substitute character as '*' const int DEFAULT_SHOW_DURATION = 1000; namespace Dali diff --git a/dali-toolkit/internal/text/hidden-text.h b/dali-toolkit/internal/text/hidden-text.h index 70d4a82..b13c263 100644 --- a/dali-toolkit/internal/text/hidden-text.h +++ b/dali-toolkit/internal/text/hidden-text.h @@ -32,6 +32,9 @@ namespace Toolkit { namespace Text { + +static constexpr const uint32_t STAR = 0x2A; // Set default substitute character as '*' + /** * Class to handle the hidden text */ diff --git a/dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp b/dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp new file mode 100644 index 0000000..87099da --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali::Toolkit::Text +{ + +void ControllerImplDataClearer::ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations) +{ + ModelPtr& model = impl.mModel; + + if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations)) + { + model->mLogicalModel->mLineBreakInfo.Clear(); + model->mLogicalModel->mParagraphInfo.Clear(); + } + + if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations)) + { + model->mLogicalModel->mScriptRuns.Clear(); + } + + if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations)) + { + model->mLogicalModel->mFontRuns.Clear(); + } + + if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count()) + { + if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations)) + { + model->mLogicalModel->mBidirectionalParagraphInfo.Clear(); + model->mLogicalModel->mCharacterDirections.Clear(); + } + + if(Controller::NO_OPERATION != (Controller::REORDER & operations)) + { + // Free the allocated memory used to store the conversion table in the bidirectional line info run. + for(Vector::Iterator it = model->mLogicalModel->mBidirectionalLineInfo.Begin(), + endIt = model->mLogicalModel->mBidirectionalLineInfo.End(); + it != endIt; + ++it) + { + BidirectionalLineInfoRun& bidiLineInfo = *it; + + free(bidiLineInfo.visualToLogicalMap); + bidiLineInfo.visualToLogicalMap = NULL; + } + model->mLogicalModel->mBidirectionalLineInfo.Clear(); + } + } + + if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) + { + model->mVisualModel->mGlyphs.Clear(); + model->mVisualModel->mGlyphsToCharacters.Clear(); + model->mVisualModel->mCharactersToGlyph.Clear(); + model->mVisualModel->mCharactersPerGlyph.Clear(); + model->mVisualModel->mGlyphsPerCharacter.Clear(); + model->mVisualModel->mGlyphPositions.Clear(); + } + + if(Controller::NO_OPERATION != (Controller::LAYOUT & operations)) + { + model->mVisualModel->mLines.Clear(); + } + + if(Controller::NO_OPERATION != (Controller::COLOR & operations)) + { + model->mVisualModel->mColorIndices.Clear(); + model->mVisualModel->mBackgroundColorIndices.Clear(); + } +} + +void ControllerImplDataClearer::ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations) +{ + const CharacterIndex endIndexPlusOne = endIndex + 1u; + ModelPtr& model = impl.mModel; + + if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations)) + { + // Clear the line break info. + LineBreakInfo* lineBreakInfoBuffer = model->mLogicalModel->mLineBreakInfo.Begin(); + + model->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex, + lineBreakInfoBuffer + endIndexPlusOne); + + // Clear the paragraphs. + ClearCharacterRuns(startIndex, + endIndex, + model->mLogicalModel->mParagraphInfo); + } + + if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations)) + { + // Clear the scripts. + ClearCharacterRuns(startIndex, + endIndex, + model->mLogicalModel->mScriptRuns); + } + + if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations)) + { + // Clear the fonts. + ClearCharacterRuns(startIndex, + endIndex, + model->mLogicalModel->mFontRuns); + } + + if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count()) + { + if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations)) + { + // Clear the bidirectional paragraph info. + ClearCharacterRuns(startIndex, + endIndex, + model->mLogicalModel->mBidirectionalParagraphInfo); + + // Clear the character's directions. + CharacterDirection* characterDirectionsBuffer = model->mLogicalModel->mCharacterDirections.Begin(); + + model->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex, + characterDirectionsBuffer + endIndexPlusOne); + } + + if(Controller::NO_OPERATION != (Controller::REORDER & operations)) + { + uint32_t startRemoveIndex = model->mLogicalModel->mBidirectionalLineInfo.Count(); + uint32_t endRemoveIndex = startRemoveIndex; + ClearCharacterRuns(startIndex, + endIndex, + model->mLogicalModel->mBidirectionalLineInfo, + startRemoveIndex, + endRemoveIndex); + + BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = model->mLogicalModel->mBidirectionalLineInfo.Begin(); + + // Free the allocated memory used to store the conversion table in the bidirectional line info run. + for(Vector::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex, + endIt = bidirectionalLineInfoBuffer + endRemoveIndex; + it != endIt; + ++it) + { + BidirectionalLineInfoRun& bidiLineInfo = *it; + + free(bidiLineInfo.visualToLogicalMap); + bidiLineInfo.visualToLogicalMap = NULL; + } + + model->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex, + bidirectionalLineInfoBuffer + endRemoveIndex); + } + } +} + +void ControllerImplDataClearer::ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations) +{ + const CharacterIndex endIndexPlusOne = endIndex + 1u; + const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex; + ModelPtr& model = impl.mModel; + TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; + + + // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers. + GlyphIndex* charactersToGlyphBuffer = model->mVisualModel->mCharactersToGlyph.Begin(); + Length* glyphsPerCharacterBuffer = model->mVisualModel->mGlyphsPerCharacter.Begin(); + + const GlyphIndex endGlyphIndexPlusOne = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex); + const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - textUpdateInfo.mStartGlyphIndex; + + if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) + { + // Update the character to glyph indices. + for(Vector::Iterator it = charactersToGlyphBuffer + endIndexPlusOne, + endIt = charactersToGlyphBuffer + model->mVisualModel->mCharactersToGlyph.Count(); + it != endIt; + ++it) + { + CharacterIndex& index = *it; + index -= numberOfGlyphsRemoved; + } + + // Clear the character to glyph conversion table. + model->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex, + charactersToGlyphBuffer + endIndexPlusOne); + + // Clear the glyphs per character table. + model->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex, + glyphsPerCharacterBuffer + endIndexPlusOne); + + // Clear the glyphs buffer. + GlyphInfo* glyphsBuffer = model->mVisualModel->mGlyphs.Begin(); + model->mVisualModel->mGlyphs.Erase(glyphsBuffer + textUpdateInfo.mStartGlyphIndex, + glyphsBuffer + endGlyphIndexPlusOne); + + CharacterIndex* glyphsToCharactersBuffer = model->mVisualModel->mGlyphsToCharacters.Begin(); + + // Update the glyph to character indices. + for(Vector::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne, + endIt = glyphsToCharactersBuffer + model->mVisualModel->mGlyphsToCharacters.Count(); + it != endIt; + ++it) + { + CharacterIndex& index = *it; + index -= numberOfCharactersRemoved; + } + + // Clear the glyphs to characters buffer. + model->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + textUpdateInfo.mStartGlyphIndex, + glyphsToCharactersBuffer + endGlyphIndexPlusOne); + + // Clear the characters per glyph buffer. + Length* charactersPerGlyphBuffer = model->mVisualModel->mCharactersPerGlyph.Begin(); + model->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + textUpdateInfo.mStartGlyphIndex, + charactersPerGlyphBuffer + endGlyphIndexPlusOne); + + // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout + if(0u != model->mVisualModel->mGlyphPositions.Count()) + { + // Clear the positions buffer. + Vector2* positionsBuffer = model->mVisualModel->mGlyphPositions.Begin(); + model->mVisualModel->mGlyphPositions.Erase(positionsBuffer + textUpdateInfo.mStartGlyphIndex, + positionsBuffer + endGlyphIndexPlusOne); + } + } + + if(Controller::NO_OPERATION != (Controller::LAYOUT & operations)) + { + // Clear the lines. + uint32_t startRemoveIndex = model->mVisualModel->mLines.Count(); + uint32_t endRemoveIndex = startRemoveIndex; + ClearCharacterRuns(startIndex, + endIndex, + model->mVisualModel->mLines, + startRemoveIndex, + endRemoveIndex); + + // Will update the glyph runs. + startRemoveIndex = model->mVisualModel->mLines.Count(); + endRemoveIndex = startRemoveIndex; + ClearGlyphRuns(textUpdateInfo.mStartGlyphIndex, + endGlyphIndexPlusOne - 1u, + model->mVisualModel->mLines, + startRemoveIndex, + endRemoveIndex); + + // Set the line index from where to insert the new laid-out lines. + textUpdateInfo.mStartLineIndex = startRemoveIndex; + + LineRun* linesBuffer = model->mVisualModel->mLines.Begin(); + model->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex, + linesBuffer + endRemoveIndex); + } + + if(Controller::NO_OPERATION != (Controller::COLOR & operations)) + { + if(0u != model->mVisualModel->mColorIndices.Count()) + { + ColorIndex* colorIndexBuffer = model->mVisualModel->mColorIndices.Begin(); + model->mVisualModel->mColorIndices.Erase(colorIndexBuffer + textUpdateInfo.mStartGlyphIndex, + colorIndexBuffer + endGlyphIndexPlusOne); + } + + if(0u != model->mVisualModel->mBackgroundColorIndices.Count()) + { + ColorIndex* backgroundColorIndexBuffer = model->mVisualModel->mBackgroundColorIndices.Begin(); + model->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + textUpdateInfo.mStartGlyphIndex, + backgroundColorIndexBuffer + endGlyphIndexPlusOne); + } + } +} + +void ControllerImplDataClearer::ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations) +{ + TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; + + if(textUpdateInfo.mClearAll || + ((0u == startIndex) && + (textUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u))) + { + ClearFullModelData(impl, operations); + } + else + { + // Clear the model data related with characters. + ClearCharacterModelData(impl, startIndex, endIndex, operations); + + // Clear the model data related with glyphs. + ClearGlyphModelData(impl, startIndex, endIndex, operations); + } + + ModelPtr& model = impl.mModel; + + // The estimated number of lines. Used to avoid reallocations when layouting. + textUpdateInfo.mEstimatedNumberOfLines = std::max(model->mVisualModel->mLines.Count(), model->mLogicalModel->mParagraphInfo.Count()); + + model->mVisualModel->ClearCaches(); +} + +} // namespace Dali::Toolkit::Text diff --git a/dali-toolkit/internal/text/text-controller-impl-data-clearer.h b/dali-toolkit/internal/text/text-controller-impl-data-clearer.h new file mode 100644 index 0000000..87d6e24 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-impl-data-clearer.h @@ -0,0 +1,81 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H + +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali::Toolkit::Text +{ + +/// Provides methods to clear some of the model data in the Text::Controller::Impl +struct ControllerImplDataClearer +{ + + /** + * @brief Helper to clear completely the parts of the model specified by the given @p operations. + * + * @note It never clears the text stored in utf32. + * + * @param[in] impl The text controller impl. + * @param[in] operations The operations required. + */ + static void ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations); + + /** + * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations. + * + * @note It never clears the text stored in utf32. + * + * @param[in] impl The text controller impl. + * @param[in] startIndex Index to the first character to be cleared. + * @param[in] endIndex Index to the last character to be cleared. + * @param[in] operations The operations required. + */ + static void ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations); + + /** + * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations. + * + * @note It never clears the text stored in utf32. + * @note Character indices are transformed to glyph indices. + * + * @param[in] impl The text controller impl. + * @param[in] startIndex Index to the first character to be cleared. + * @param[in] endIndex Index to the last character to be cleared. + * @param[in] operations The operations required. + */ + static void ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations); + + /** + * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex. + * + * @note It never clears the text stored in utf32. + * + * @param[in] impl The text controller impl. + * @param[in] startIndex Index to the first character to be cleared. + * @param[in] endIndex Index to the last character to be cleared. + * @param[in] operations The operations required. + */ + static void ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations); +}; + +} // namespace Dali::Toolkit::Text + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 4334f0e..8a1dd76 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -19,8 +19,10 @@ #include // EXTERNAL INCLUDES +#include #include #include +#include // INTERNAL INCLUDES #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +132,243 @@ void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const font } } } + +void ChangeTextControllerState(Controller::Impl& impl, EventData::State newState) +{ + EventData* eventData = impl.mEventData; + + if(nullptr == eventData) + { + // Nothing to do if there is no text input. + return; + } + + DecoratorPtr& decorator = eventData->mDecorator; + if(!decorator) + { + // Nothing to do if there is no decorator. + return; + } + + DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d newstate:%d\n", eventData->mState, newState); + + if(eventData->mState != newState) + { + eventData->mPreviousState = eventData->mState; + eventData->mState = newState; + + switch(eventData->mState) + { + case EventData::INACTIVE: + { + decorator->SetActiveCursor(ACTIVE_CURSOR_NONE); + decorator->StopCursorBlink(); + decorator->SetHandleActive(GRAB_HANDLE, false); + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + decorator->SetPopupActive(false); + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::INTERRUPTED: + { + decorator->SetHandleActive(GRAB_HANDLE, false); + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + decorator->SetPopupActive(false); + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::SELECTING: + { + decorator->SetActiveCursor(ACTIVE_CURSOR_NONE); + decorator->StopCursorBlink(); + decorator->SetHandleActive(GRAB_HANDLE, false); + if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true); + } + decorator->SetHighlightActive(true); + if(eventData->mGrabHandlePopupEnabled) + { + impl.SetPopupButtons(); + decorator->SetPopupActive(true); + } + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::EDITING: + { + decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); + if(eventData->mCursorBlinkEnabled) + { + decorator->StartCursorBlink(); + } + // Grab handle is not shown until a tap is received whilst EDITING + decorator->SetHandleActive(GRAB_HANDLE, false); + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + if(eventData->mGrabHandlePopupEnabled) + { + decorator->SetPopupActive(false); + } + eventData->mDecoratorUpdated = true; + break; + } + case EventData::EDITING_WITH_POPUP: + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState); + + decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); + if(eventData->mCursorBlinkEnabled) + { + decorator->StartCursorBlink(); + } + if(eventData->mSelectionEnabled) + { + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + } + else if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(GRAB_HANDLE, true); + } + if(eventData->mGrabHandlePopupEnabled) + { + impl.SetPopupButtons(); + decorator->SetPopupActive(true); + } + eventData->mDecoratorUpdated = true; + break; + } + case EventData::EDITING_WITH_GRAB_HANDLE: + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState); + + decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); + if(eventData->mCursorBlinkEnabled) + { + decorator->StartCursorBlink(); + } + // Grab handle is not shown until a tap is received whilst EDITING + if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(GRAB_HANDLE, true); + } + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + if(eventData->mGrabHandlePopupEnabled) + { + decorator->SetPopupActive(false); + } + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::SELECTION_HANDLE_PANNING: + { + decorator->SetActiveCursor(ACTIVE_CURSOR_NONE); + decorator->StopCursorBlink(); + decorator->SetHandleActive(GRAB_HANDLE, false); + if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true); + } + decorator->SetHighlightActive(true); + if(eventData->mGrabHandlePopupEnabled) + { + decorator->SetPopupActive(false); + } + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::GRAB_HANDLE_PANNING: + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState); + + decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); + if(eventData->mCursorBlinkEnabled) + { + decorator->StartCursorBlink(); + } + if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(GRAB_HANDLE, true); + } + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + if(eventData->mGrabHandlePopupEnabled) + { + decorator->SetPopupActive(false); + } + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::EDITING_WITH_PASTE_POPUP: + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState); + + decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); + if(eventData->mCursorBlinkEnabled) + { + decorator->StartCursorBlink(); + } + + if(eventData->mGrabHandleEnabled) + { + decorator->SetHandleActive(GRAB_HANDLE, true); + } + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(false); + + if(eventData->mGrabHandlePopupEnabled) + { + impl.SetPopupButtons(); + decorator->SetPopupActive(true); + } + eventData->mDecoratorUpdated = true; + break; + } + + case EventData::TEXT_PANNING: + { + decorator->SetActiveCursor(ACTIVE_CURSOR_NONE); + decorator->StopCursorBlink(); + decorator->SetHandleActive(GRAB_HANDLE, false); + if(eventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) || + decorator->IsHandleActive(RIGHT_SELECTION_HANDLE)) + { + decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); + decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); + decorator->SetHighlightActive(true); + } + + if(eventData->mGrabHandlePopupEnabled) + { + decorator->SetPopupActive(false); + } + + eventData->mDecoratorUpdated = true; + break; + } + } + } +} + } // unnamed Namespace EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext) @@ -268,6 +508,19 @@ void Controller::Impl::GetText(CharacterIndex index, std::string& text) const } } +Dali::LayoutDirection::Type Controller::Impl::GetLayoutDirection(Dali::Actor& actor) const +{ + if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE || + (mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged)) + { + return static_cast(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); + } + else + { + return static_cast(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); + } +} + void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters) { mTextUpdateInfo.mParagraphCharacterIndex = 0u; @@ -353,286 +606,9 @@ void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters) mTextUpdateInfo.mStartGlyphIndex = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex); } -void Controller::Impl::ClearFullModelData(OperationsMask operations) -{ - if(NO_OPERATION != (GET_LINE_BREAKS & operations)) - { - mModel->mLogicalModel->mLineBreakInfo.Clear(); - mModel->mLogicalModel->mParagraphInfo.Clear(); - } - - if(NO_OPERATION != (GET_SCRIPTS & operations)) - { - mModel->mLogicalModel->mScriptRuns.Clear(); - } - - if(NO_OPERATION != (VALIDATE_FONTS & operations)) - { - mModel->mLogicalModel->mFontRuns.Clear(); - } - - if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count()) - { - if(NO_OPERATION != (BIDI_INFO & operations)) - { - mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear(); - mModel->mLogicalModel->mCharacterDirections.Clear(); - } - - if(NO_OPERATION != (REORDER & operations)) - { - // Free the allocated memory used to store the conversion table in the bidirectional line info run. - for(Vector::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(), - endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End(); - it != endIt; - ++it) - { - BidirectionalLineInfoRun& bidiLineInfo = *it; - - free(bidiLineInfo.visualToLogicalMap); - bidiLineInfo.visualToLogicalMap = NULL; - } - mModel->mLogicalModel->mBidirectionalLineInfo.Clear(); - } - } - - if(NO_OPERATION != (SHAPE_TEXT & operations)) - { - mModel->mVisualModel->mGlyphs.Clear(); - mModel->mVisualModel->mGlyphsToCharacters.Clear(); - mModel->mVisualModel->mCharactersToGlyph.Clear(); - mModel->mVisualModel->mCharactersPerGlyph.Clear(); - mModel->mVisualModel->mGlyphsPerCharacter.Clear(); - mModel->mVisualModel->mGlyphPositions.Clear(); - } - - if(NO_OPERATION != (LAYOUT & operations)) - { - mModel->mVisualModel->mLines.Clear(); - } - - if(NO_OPERATION != (COLOR & operations)) - { - mModel->mVisualModel->mColorIndices.Clear(); - mModel->mVisualModel->mBackgroundColorIndices.Clear(); - } -} - -void Controller::Impl::ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations) -{ - const CharacterIndex endIndexPlusOne = endIndex + 1u; - - if(NO_OPERATION != (GET_LINE_BREAKS & operations)) - { - // Clear the line break info. - LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin(); - - mModel->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex, - lineBreakInfoBuffer + endIndexPlusOne); - - // Clear the paragraphs. - ClearCharacterRuns(startIndex, - endIndex, - mModel->mLogicalModel->mParagraphInfo); - } - - if(NO_OPERATION != (GET_SCRIPTS & operations)) - { - // Clear the scripts. - ClearCharacterRuns(startIndex, - endIndex, - mModel->mLogicalModel->mScriptRuns); - } - - if(NO_OPERATION != (VALIDATE_FONTS & operations)) - { - // Clear the fonts. - ClearCharacterRuns(startIndex, - endIndex, - mModel->mLogicalModel->mFontRuns); - } - - if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count()) - { - if(NO_OPERATION != (BIDI_INFO & operations)) - { - // Clear the bidirectional paragraph info. - ClearCharacterRuns(startIndex, - endIndex, - mModel->mLogicalModel->mBidirectionalParagraphInfo); - - // Clear the character's directions. - CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin(); - - mModel->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex, - characterDirectionsBuffer + endIndexPlusOne); - } - - if(NO_OPERATION != (REORDER & operations)) - { - uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count(); - uint32_t endRemoveIndex = startRemoveIndex; - ClearCharacterRuns(startIndex, - endIndex, - mModel->mLogicalModel->mBidirectionalLineInfo, - startRemoveIndex, - endRemoveIndex); - - BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(); - - // Free the allocated memory used to store the conversion table in the bidirectional line info run. - for(Vector::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex, - endIt = bidirectionalLineInfoBuffer + endRemoveIndex; - it != endIt; - ++it) - { - BidirectionalLineInfoRun& bidiLineInfo = *it; - - free(bidiLineInfo.visualToLogicalMap); - bidiLineInfo.visualToLogicalMap = NULL; - } - - mModel->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex, - bidirectionalLineInfoBuffer + endRemoveIndex); - } - } -} - -void Controller::Impl::ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations) -{ - const CharacterIndex endIndexPlusOne = endIndex + 1u; - const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex; - - // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers. - GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin(); - Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin(); - - const GlyphIndex endGlyphIndexPlusOne = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex); - const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex; - - if(NO_OPERATION != (SHAPE_TEXT & operations)) - { - // Update the character to glyph indices. - for(Vector::Iterator it = charactersToGlyphBuffer + endIndexPlusOne, - endIt = charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count(); - it != endIt; - ++it) - { - CharacterIndex& index = *it; - index -= numberOfGlyphsRemoved; - } - - // Clear the character to glyph conversion table. - mModel->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex, - charactersToGlyphBuffer + endIndexPlusOne); - - // Clear the glyphs per character table. - mModel->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex, - glyphsPerCharacterBuffer + endIndexPlusOne); - - // Clear the glyphs buffer. - GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin(); - mModel->mVisualModel->mGlyphs.Erase(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, - glyphsBuffer + endGlyphIndexPlusOne); - - CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin(); - - // Update the glyph to character indices. - for(Vector::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne, - endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count(); - it != endIt; - ++it) - { - CharacterIndex& index = *it; - index -= numberOfCharactersRemoved; - } - - // Clear the glyphs to characters buffer. - mModel->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex, - glyphsToCharactersBuffer + endGlyphIndexPlusOne); - - // Clear the characters per glyph buffer. - Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin(); - mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex, - charactersPerGlyphBuffer + endGlyphIndexPlusOne); - - // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout - if(0u != mModel->mVisualModel->mGlyphPositions.Count()) - { - // Clear the positions buffer. - Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin(); - mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex, - positionsBuffer + endGlyphIndexPlusOne); - } - } - - if(NO_OPERATION != (LAYOUT & operations)) - { - // Clear the lines. - uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count(); - uint32_t endRemoveIndex = startRemoveIndex; - ClearCharacterRuns(startIndex, - endIndex, - mModel->mVisualModel->mLines, - startRemoveIndex, - endRemoveIndex); - - // Will update the glyph runs. - startRemoveIndex = mModel->mVisualModel->mLines.Count(); - endRemoveIndex = startRemoveIndex; - ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex, - endGlyphIndexPlusOne - 1u, - mModel->mVisualModel->mLines, - startRemoveIndex, - endRemoveIndex); - - // Set the line index from where to insert the new laid-out lines. - mTextUpdateInfo.mStartLineIndex = startRemoveIndex; - - LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin(); - mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex, - linesBuffer + endRemoveIndex); - } - - if(NO_OPERATION != (COLOR & operations)) - { - if(0u != mModel->mVisualModel->mColorIndices.Count()) - { - ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin(); - mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex, - colorIndexBuffer + endGlyphIndexPlusOne); - } - - if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count()) - { - ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin(); - mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex, - backgroundColorIndexBuffer + endGlyphIndexPlusOne); - } - } -} - void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations) { - if(mTextUpdateInfo.mClearAll || - ((0u == startIndex) && - (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u))) - { - ClearFullModelData(operations); - } - else - { - // Clear the model data related with characters. - ClearCharacterModelData(startIndex, endIndex, operations); - - // Clear the model data related with glyphs. - ClearGlyphModelData(startIndex, endIndex, operations); - } - - // The estimated number of lines. Used to avoid reallocations when layouting. - mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count()); - - mModel->mVisualModel->ClearCaches(); + ControllerImplDataClearer::ClearModelData(*this, startIndex, endIndex, operations); } bool Controller::Impl::UpdateModel(OperationsMask operationsRequired) @@ -664,6 +640,32 @@ float Controller::Impl::GetDefaultFontLineHeight() return (fontMetrics.ascender - fontMetrics.descender); } +bool Controller::Impl::SetDefaultLineSpacing(float lineSpacing) +{ + if(std::fabs(lineSpacing - mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000) + { + mLayoutEngine.SetDefaultLineSpacing(lineSpacing); + mRecalculateNaturalSize = true; + + RelayoutForNewLineSize(); + return true; + } + return false; +} + +bool Controller::Impl::SetDefaultLineSize(float lineSize) +{ + if(std::fabs(lineSize - mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000) + { + mLayoutEngine.SetDefaultLineSize(lineSize); + mRecalculateNaturalSize = true; + + RelayoutForNewLineSize(); + return true; + } + return false; +} + void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd) { if(nullptr == mEventData) @@ -791,6 +793,21 @@ void Controller::Impl::SetEditable(bool editable) } } +void Controller::Impl::UpdateAfterFontChange(const std::string& newDefaultFont) +{ + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n"); + + if(!mFontDefaults->familyDefined) // If user defined font then should not update when system font changes + { + DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str()); + mFontDefaults->mFontDescription.family = newDefaultFont; + + ClearFontData(); + + RequestRelayout(); + } +} + void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval) { if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition) @@ -1008,222 +1025,7 @@ void Controller::Impl::SetPopupButtons() void Controller::Impl::ChangeState(EventData::State newState) { - if(nullptr == mEventData) - { - // Nothing to do if there is no text input. - return; - } - - DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d newstate:%d\n", mEventData->mState, newState); - - if(mEventData->mState != newState) - { - mEventData->mPreviousState = mEventData->mState; - mEventData->mState = newState; - - switch(mEventData->mState) - { - case EventData::INACTIVE: - { - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE); - mEventData->mDecorator->StopCursorBlink(); - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - mEventData->mDecorator->SetPopupActive(false); - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::INTERRUPTED: - { - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - mEventData->mDecorator->SetPopupActive(false); - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::SELECTING: - { - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE); - mEventData->mDecorator->StopCursorBlink(); - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true); - } - mEventData->mDecorator->SetHighlightActive(true); - if(mEventData->mGrabHandlePopupEnabled) - { - SetPopupButtons(); - mEventData->mDecorator->SetPopupActive(true); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::EDITING: - { - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); - if(mEventData->mCursorBlinkEnabled) - { - mEventData->mDecorator->StartCursorBlink(); - } - // Grab handle is not shown until a tap is received whilst EDITING - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - if(mEventData->mGrabHandlePopupEnabled) - { - mEventData->mDecorator->SetPopupActive(false); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::EDITING_WITH_POPUP: - { - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState); - - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); - if(mEventData->mCursorBlinkEnabled) - { - mEventData->mDecorator->StartCursorBlink(); - } - if(mEventData->mSelectionEnabled) - { - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - } - else if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true); - } - if(mEventData->mGrabHandlePopupEnabled) - { - SetPopupButtons(); - mEventData->mDecorator->SetPopupActive(true); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::EDITING_WITH_GRAB_HANDLE: - { - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState); - - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); - if(mEventData->mCursorBlinkEnabled) - { - mEventData->mDecorator->StartCursorBlink(); - } - // Grab handle is not shown until a tap is received whilst EDITING - if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true); - } - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - if(mEventData->mGrabHandlePopupEnabled) - { - mEventData->mDecorator->SetPopupActive(false); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::SELECTION_HANDLE_PANNING: - { - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE); - mEventData->mDecorator->StopCursorBlink(); - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true); - } - mEventData->mDecorator->SetHighlightActive(true); - if(mEventData->mGrabHandlePopupEnabled) - { - mEventData->mDecorator->SetPopupActive(false); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::GRAB_HANDLE_PANNING: - { - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState); - - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); - if(mEventData->mCursorBlinkEnabled) - { - mEventData->mDecorator->StartCursorBlink(); - } - if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true); - } - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - if(mEventData->mGrabHandlePopupEnabled) - { - mEventData->mDecorator->SetPopupActive(false); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::EDITING_WITH_PASTE_POPUP: - { - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState); - - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY); - if(mEventData->mCursorBlinkEnabled) - { - mEventData->mDecorator->StartCursorBlink(); - } - - if(mEventData->mGrabHandleEnabled) - { - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true); - } - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(false); - - if(mEventData->mGrabHandlePopupEnabled) - { - SetPopupButtons(); - mEventData->mDecorator->SetPopupActive(true); - } - mEventData->mDecoratorUpdated = true; - break; - } - case EventData::TEXT_PANNING: - { - mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE); - mEventData->mDecorator->StopCursorBlink(); - mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false); - if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) || - mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE)) - { - mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false); - mEventData->mDecorator->SetHighlightActive(true); - } - - if(mEventData->mGrabHandlePopupEnabled) - { - mEventData->mDecorator->SetPopupActive(false); - } - - mEventData->mDecoratorUpdated = true; - break; - } - } - } + ChangeTextControllerState(*this, newState); } void Controller::Impl::GetCursorPosition(CharacterIndex logical, @@ -1843,4 +1645,197 @@ void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearP } } +void Controller::Impl::SetAutoScrollEnabled(bool enable) +{ + if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) + { + mOperationsPending = static_cast(mOperationsPending | + LAYOUT | + ALIGN | + UPDATE_LAYOUT_SIZE | + REORDER); + + if(enable) + { + DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n"); + mOperationsPending = static_cast(mOperationsPending | UPDATE_DIRECTION); + } + else + { + DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n"); + } + + mIsAutoScrollEnabled = enable; + RequestRelayout(); + } + else + { + DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n"); + mIsAutoScrollEnabled = false; + } +} + +void Controller::Impl::SetEnableCursorBlink(bool enable) +{ + DALI_ASSERT_DEBUG(NULL != mEventData && "TextInput disabled"); + + if(mEventData) + { + mEventData->mCursorBlinkEnabled = enable; + + if(!enable && mEventData->mDecorator) + { + mEventData->mDecorator->StopCursorBlink(); + } + } +} + +void Controller::Impl::SetMultiLineEnabled(bool enable) +{ + const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX; + + if(layout != mLayoutEngine.GetLayout()) + { + // Set the layout type. + mLayoutEngine.SetLayout(layout); + + // Set the flags to redo the layout operations + const OperationsMask layoutOperations = static_cast(LAYOUT | + UPDATE_LAYOUT_SIZE | + ALIGN | + REORDER); + + mTextUpdateInfo.mFullRelayoutNeeded = true; + mOperationsPending = static_cast(mOperationsPending | layoutOperations); + + // Need to recalculate natural size + mRecalculateNaturalSize = true; + + RequestRelayout(); + } +} + +void Controller::Impl::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment) +{ + if(alignment != mModel->mHorizontalAlignment) + { + // Set the alignment. + mModel->mHorizontalAlignment = alignment; + + // Set the flag to redo the alignment operation. + mOperationsPending = static_cast(mOperationsPending | ALIGN); + + if(mEventData) + { + mEventData->mUpdateAlignment = true; + + // Update the cursor if it's in editing mode + if(EventData::IsEditingState(mEventData->mState)) + { + ChangeState(EventData::EDITING); + mEventData->mUpdateCursorPosition = true; + } + } + + RequestRelayout(); + } +} + +void Controller::Impl::SetVerticalAlignment(VerticalAlignment::Type alignment) +{ + if(alignment != mModel->mVerticalAlignment) + { + // Set the alignment. + mModel->mVerticalAlignment = alignment; + mOperationsPending = static_cast(mOperationsPending | ALIGN); + RequestRelayout(); + } +} + +void Controller::Impl::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode) +{ + if(lineWrapMode != mModel->mLineWrapMode) + { + // Update Text layout for applying wrap mode + mOperationsPending = static_cast(mOperationsPending | + ALIGN | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER); + + if((mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || + (mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break + { + mOperationsPending = static_cast(mOperationsPending | GET_LINE_BREAKS); + } + + // Set the text wrap mode. + mModel->mLineWrapMode = lineWrapMode; + + mTextUpdateInfo.mCharacterIndex = 0u; + mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters; + mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count(); + + // Request relayout + RequestRelayout(); + } +} + +void Controller::Impl::SetDefaultColor(const Vector4& color) +{ + mTextColor = color; + + if(!IsShowingPlaceholderText()) + { + mModel->mVisualModel->SetTextColor(color); + mModel->mLogicalModel->mColorRuns.Clear(); + mOperationsPending = static_cast(mOperationsPending | COLOR); + RequestRelayout(); + } +} + +void Controller::Impl::ClearFontData() +{ + if(mFontDefaults) + { + mFontDefaults->mFontId = 0u; // Remove old font ID + } + + // Set flags to update the model. + mTextUpdateInfo.mCharacterIndex = 0u; + mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters; + mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count(); + + mTextUpdateInfo.mClearAll = true; + mTextUpdateInfo.mFullRelayoutNeeded = true; + mRecalculateNaturalSize = true; + + mOperationsPending = static_cast(mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + BIDI_INFO | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN); +} + +void Controller::Impl::ClearStyleData() +{ + mModel->mLogicalModel->mColorRuns.Clear(); + mModel->mLogicalModel->ClearFontDescriptionRuns(); +} + + +void Controller::Impl::ResetScrollPosition() +{ + if(mEventData) + { + // Reset the scroll position. + mModel->mScrollPosition = Vector2::ZERO; + mEventData->mScrollAfterUpdatePosition = true; + } +} + } // namespace Dali::Toolkit::Text diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index 219ca72..814f3a8 100644 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -545,6 +545,11 @@ struct Controller::Impl } /** + * @copydoc Controller::GetLayoutDirection() + */ + Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const; + + /** * @brief Calculates the start character index of the first paragraph to be updated and * the end character index of the last paragraph to be updated. * @@ -553,36 +558,6 @@ struct Controller::Impl void CalculateTextUpdateIndices(Length& numberOfCharacters); /** - * @brief Helper to clear completely the parts of the model specified by the given @p operations. - * - * @note It never clears the text stored in utf32. - */ - void ClearFullModelData(OperationsMask operations); - - /** - * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations. - * - * @note It never clears the text stored in utf32. - * - * @param[in] startIndex Index to the first character to be cleared. - * @param[in] endIndex Index to the last character to be cleared. - * @param[in] operations The operations required. - */ - void ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations); - - /** - * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations. - * - * @note It never clears the text stored in utf32. - * @note Character indices are transformed to glyph indices. - * - * @param[in] startIndex Index to the first character to be cleared. - * @param[in] endIndex Index to the last character to be cleared. - * @param[in] operations The operations required. - */ - void ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations); - - /** * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex. * * @note It never clears the text stored in utf32. @@ -620,6 +595,16 @@ struct Controller::Impl float GetDefaultFontLineHeight(); /** + * @copydoc Controller::SetDefaultLineSpacing + */ + bool SetDefaultLineSpacing(float lineSpacing); + + /** + * @copydoc Controller::SetDefaultLineSize + */ + bool SetDefaultLineSize(float lineSize); + + /** * @copydoc Text::Controller::GetPrimaryCursorPosition() */ CharacterIndex GetPrimaryCursorPosition() const; @@ -650,6 +635,11 @@ struct Controller::Impl void SetEditable(bool editable); /** + * @copydoc Controller::UpdateAfterFontChange + */ + void UpdateAfterFontChange(const std::string& newDefaultFont); + + /** * @brief Retrieves the selected text. It removes the text if the @p deleteAfterRetrieval parameter is @e true. * * @param[out] selectedText The selected text encoded in utf8. @@ -801,6 +791,55 @@ struct Controller::Impl */ float GetVerticalScrollPosition(); + /** + * @copydoc Controller::SetAutoScrollEnabled() + */ + void SetAutoScrollEnabled(bool enable); + + /** + * @copydoc Controller::SetEnableCursorBlink() + */ + void SetEnableCursorBlink(bool enable); + + /** + * @copydoc Controller::SetMultiLineEnabled() + */ + void SetMultiLineEnabled(bool enable); + + /** + * @copydoc Controller::SetHorizontalAlignment() + */ + void SetHorizontalAlignment(HorizontalAlignment::Type alignment); + + /** + * @copydoc Controller::SetVerticalAlignment() + */ + void SetVerticalAlignment(VerticalAlignment::Type alignment); + + /** + * @copydoc Controller::SetLineWrapMode() + */ + void SetLineWrapMode(Text::LineWrap::Mode textWarpMode); + + /** + * @copydoc Controller::SetDefaultColor() + */ + void SetDefaultColor(const Vector4& color); + + /** + * @brief Helper to clear font-specific data (only). + */ + void ClearFontData(); + + /** + * @brief Helper to clear text's style data. + */ + void ClearStyleData(); + + /** + * @brief Used to reset the scroll position after setting a new text. + */ + void ResetScrollPosition(); public: /** @@ -872,6 +911,7 @@ public: float mTextFitMaxSize; ///< Maximum Font Size for text fit. Default 100 float mTextFitStepSize; ///< Step Size for font intervalse. Default 1 bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled. + float mTextFitChanged; ///< Whether the text fit property has changed. float mFontSizeScale; ///< Scale value for Font Size. Default 1.0 bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed. diff --git a/dali-toolkit/internal/text/text-controller-relayouter.cpp b/dali-toolkit/internal/text/text-controller-relayouter.cpp index 4c71934..c38f92e 100644 --- a/dali-toolkit/internal/text/text-controller-relayouter.cpp +++ b/dali-toolkit/internal/text/text-controller-relayouter.cpp @@ -170,7 +170,7 @@ bool Controller::Relayouter::CheckForTextFit(Controller& controller, float point TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; impl.mFontDefaults->mFitPointSize = pointSize; impl.mFontDefaults->sizeDefined = true; - controller.ClearFontData(); + impl.ClearFontData(); // Operations that can be done only once until the text changes. const OperationsMask onlyOnceOperations = static_cast(CONVERT_TO_UTF32 | @@ -216,6 +216,7 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const float minPointSize = impl.mTextFitMinSize; float maxPointSize = impl.mTextFitMaxSize; float pointInterval = impl.mTextFitStepSize; + float currentFitPointSize = impl.mFontDefaults->mFitPointSize; model->mElideEnabled = false; Vector pointSizeArray; @@ -255,9 +256,13 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const } model->mElideEnabled = actualellipsis; + if(currentFitPointSize != pointSizeArray[bestSizeIndex]) + { + impl.mTextFitChanged = true; + } impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex]; impl.mFontDefaults->sizeDefined = true; - controller.ClearFontData(); + impl.ClearFontData(); } } @@ -561,7 +566,7 @@ bool Controller::Relayouter::DoRelayout(Controller& controller, const Size& size // Reset the scroll position in inactive state if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE)) { - controller.ResetScrollPosition(); + impl.ResetScrollPosition(); } } diff --git a/dali-toolkit/internal/text/text-controller-text-updater.cpp b/dali-toolkit/internal/text/text-controller-text-updater.cpp index 75ea73c..8a19786 100644 --- a/dali-toolkit/internal/text/text-controller-text-updater.cpp +++ b/dali-toolkit/internal/text/text-controller-text-updater.cpp @@ -55,7 +55,7 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string& ResetText(controller); // Remove the style. - controller.ClearStyleData(); + impl.ClearStyleData(); CharacterIndex lastCursorIndex = 0u; @@ -150,7 +150,7 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string& controller.ResetCursorPosition(lastCursorIndex); // Scrolls the text to make the cursor visible. - controller.ResetScrollPosition(); + impl.ResetScrollPosition(); impl.RequestRelayout(); diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 19af999..4ec306b 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -138,7 +138,7 @@ void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType) mImpl->mMetrics->SetGlyphType(glyphType); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -170,39 +170,12 @@ bool Controller::HasAnchors() const void Controller::SetAutoScrollEnabled(bool enable) { DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this); - - if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) - { - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | - LAYOUT | - ALIGN | - UPDATE_LAYOUT_SIZE | - REORDER); - - if(enable) - { - DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n"); - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | UPDATE_DIRECTION); - } - else - { - DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n"); - } - - mImpl->mIsAutoScrollEnabled = enable; - mImpl->RequestRelayout(); - } - else - { - DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n"); - mImpl->mIsAutoScrollEnabled = false; - } + mImpl->SetAutoScrollEnabled(enable); } bool Controller::IsAutoScrollEnabled() const { DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false"); - return mImpl->mIsAutoScrollEnabled; } @@ -272,17 +245,7 @@ int Controller::GetMaximumNumberOfCharacters() void Controller::SetEnableCursorBlink(bool enable) { - DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled"); - - if(mImpl->mEventData) - { - mImpl->mEventData->mCursorBlinkEnabled = enable; - - if(!enable && mImpl->mEventData->mDecorator) - { - mImpl->mEventData->mDecorator->StopCursorBlink(); - } - } + mImpl->SetEnableCursorBlink(enable); } bool Controller::GetEnableCursorBlink() const @@ -292,27 +255,7 @@ bool Controller::GetEnableCursorBlink() const void Controller::SetMultiLineEnabled(bool enable) { - const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX; - - if(layout != mImpl->mLayoutEngine.GetLayout()) - { - // Set the layout type. - mImpl->mLayoutEngine.SetLayout(layout); - - // Set the flags to redo the layout operations - const OperationsMask layoutOperations = static_cast(LAYOUT | - UPDATE_LAYOUT_SIZE | - ALIGN | - REORDER); - - mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true; - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | layoutOperations); - - // Need to recalculate natural size - mImpl->mRecalculateNaturalSize = true; - - mImpl->RequestRelayout(); - } + mImpl->SetMultiLineEnabled(enable); } bool Controller::IsMultiLineEnabled() const @@ -322,28 +265,7 @@ bool Controller::IsMultiLineEnabled() const void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment) { - if(alignment != mImpl->mModel->mHorizontalAlignment) - { - // Set the alignment. - mImpl->mModel->mHorizontalAlignment = alignment; - - // Set the flag to redo the alignment operation. - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | ALIGN); - - if(mImpl->mEventData) - { - mImpl->mEventData->mUpdateAlignment = true; - - // Update the cursor if it's in editing mode - if(EventData::IsEditingState(mImpl->mEventData->mState)) - { - mImpl->ChangeState(EventData::EDITING); - mImpl->mEventData->mUpdateCursorPosition = true; - } - } - - mImpl->RequestRelayout(); - } + mImpl->SetHorizontalAlignment(alignment); } Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const @@ -353,13 +275,7 @@ Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment) { - if(alignment != mImpl->mModel->mVerticalAlignment) - { - // Set the alignment. - mImpl->mModel->mVerticalAlignment = alignment; - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | ALIGN); - mImpl->RequestRelayout(); - } + mImpl->SetVerticalAlignment(alignment); } VerticalAlignment::Type Controller::GetVerticalAlignment() const @@ -417,31 +333,7 @@ bool Controller::IsShowingRealText() const void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode) { - if(lineWrapMode != mImpl->mModel->mLineWrapMode) - { - // Update Text layout for applying wrap mode - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | - ALIGN | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER); - - if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || - (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break - { - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | GET_LINE_BREAKS); - } - - // Set the text wrap mode. - mImpl->mModel->mLineWrapMode = lineWrapMode; - - mImpl->mTextUpdateInfo.mCharacterIndex = 0u; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - - // Request relayout - mImpl->RequestRelayout(); - } + mImpl->SetLineWrapMode(lineWrapMode); } Text::LineWrap::Mode Controller::GetLineWrapMode() const @@ -470,6 +362,16 @@ bool Controller::IsTextFitEnabled() const return mImpl->mTextFitEnabled; } +void Controller::SetTextFitChanged(bool changed) +{ + mImpl->mTextFitChanged = changed; +} + +bool Controller::IsTextFitChanged() const +{ + return mImpl->mTextFitChanged; +} + void Controller::SetTextFitMinSize(float minSize, FontSizeType type) { mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize); @@ -510,6 +412,11 @@ Vector2 Controller::GetTextFitContentSize() const return mImpl->mTextFitContentSize; } +float Controller::GetTextFitPointSize() const +{ + return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f; +} + void Controller::SetPlaceholderTextElideEnabled(bool enabled) { PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled); @@ -590,17 +497,7 @@ void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) con void Controller::UpdateAfterFontChange(const std::string& newDefaultFont) { - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n"); - - if(!mImpl->mFontDefaults->familyDefined) // If user defined font then should not update when system font changes - { - DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str()); - mImpl->mFontDefaults->mFontDescription.family = newDefaultFont; - - ClearFontData(); - - mImpl->RequestRelayout(); - } + mImpl->UpdateAfterFontChange(newDefaultFont); } void Controller::RetrieveSelection(std::string& selectedText) const @@ -640,7 +537,7 @@ void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -671,7 +568,7 @@ void Controller::SetDefaultFontWeight(FontWeight weight) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -712,7 +609,7 @@ void Controller::SetDefaultFontWidth(FontWidth width) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -753,7 +650,7 @@ void Controller::SetDefaultFontSlant(FontSlant slant) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -791,7 +688,7 @@ void Controller::SetFontSizeScale(float scale) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -812,7 +709,7 @@ void Controller::SetDefaultFontSize(float fontSize, FontSizeType type) UpdateCursorPosition(mImpl->mEventData); // Clear the font-specific data - ClearFontData(); + mImpl->ClearFontData(); mImpl->RequestRelayout(); } @@ -838,15 +735,7 @@ float Controller::GetPlaceholderTextFontSize(FontSizeType type) const void Controller::SetDefaultColor(const Vector4& color) { - mImpl->mTextColor = color; - - if(!mImpl->IsShowingPlaceholderText()) - { - mImpl->mModel->mVisualModel->SetTextColor(color); - mImpl->mModel->mLogicalModel->mColorRuns.Clear(); - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | COLOR); - mImpl->RequestRelayout(); - } + mImpl->SetDefaultColor(color); } const Vector4& Controller::GetDefaultColor() const @@ -1001,15 +890,7 @@ const std::string& Controller::GetDefaultOutlineProperties() const bool Controller::SetDefaultLineSpacing(float lineSpacing) { - if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000) - { - mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing); - mImpl->mRecalculateNaturalSize = true; - - mImpl->RelayoutForNewLineSize(); - return true; - } - return false; + return mImpl->SetDefaultLineSpacing(lineSpacing); } float Controller::GetDefaultLineSpacing() const @@ -1019,15 +900,7 @@ float Controller::GetDefaultLineSpacing() const bool Controller::SetDefaultLineSize(float lineSize) { - if(std::fabs(lineSize - mImpl->mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000) - { - mImpl->mLayoutEngine.SetDefaultLineSize(lineSize); - mImpl->mRecalculateNaturalSize = true; - - mImpl->RelayoutForNewLineSize(); - return true; - } - return false; + return mImpl->SetDefaultLineSize(lineSize); } float Controller::GetDefaultLineSize() const @@ -1731,39 +1604,6 @@ void Controller::ShowPlaceholderText() PlaceholderHandler::ShowPlaceholderText(*this); } -void Controller::ClearFontData() -{ - if(mImpl->mFontDefaults) - { - mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID - } - - // Set flags to update the model. - mImpl->mTextUpdateInfo.mCharacterIndex = 0u; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - - mImpl->mTextUpdateInfo.mClearAll = true; - mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true; - mImpl->mRecalculateNaturalSize = true; - - mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - BIDI_INFO | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN); -} - -void Controller::ClearStyleData() -{ - mImpl->mModel->mLogicalModel->mColorRuns.Clear(); - mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns(); -} - void Controller::ResetCursorPosition(CharacterIndex cursorIndex) { // Reset the cursor position @@ -1781,20 +1621,7 @@ void Controller::ResetCursorPosition(CharacterIndex cursorIndex) CharacterIndex Controller::GetCursorPosition() { - if(!mImpl->mEventData) - return 0; - - return mImpl->mEventData->mPrimaryCursorPosition; -} - -void Controller::ResetScrollPosition() -{ - if(mImpl->mEventData) - { - // Reset the scroll position. - mImpl->mModel->mScrollPosition = Vector2::ZERO; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } + return mImpl->mEventData ? mImpl->mEventData->mPrimaryCursorPosition : 0; } void Controller::SetControlInterface(ControlInterface* controlInterface) diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index ec3cbb9..a5bc8b4 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -482,6 +482,27 @@ public: // Configure the text controller. Vector2 GetTextFitContentSize() const; /** + * @brief Retrieve the fited point size. + * + * @return The fited point size. + */ + float GetTextFitPointSize() const; + + /** + * @brief Sets whether the text fit properties have changed. + * + * @param[in] changed Whether to changed the text fit. + */ + void SetTextFitChanged(bool changed); + + /** + * @brief Whether the text fit properties are changed or not. + * + * @return True if the text fit properties are changed + */ + bool IsTextFitChanged() const; + + /** * @brief Enable or disable the placeholder text elide. * @param enabled Whether to enable the placeholder text elide. */ @@ -1881,21 +1902,6 @@ private: // Helpers. */ void ShowPlaceholderText(); - /** - * @brief Helper to clear font-specific data (only). - */ - void ClearFontData(); - - /** - * @brief Helper to clear text's style data. - */ - void ClearStyleData(); - - /** - * @brief Used to reset the scroll position after setting a new text. - */ - void ResetScrollPosition(); - private: // Private contructors & copy operator. /** * @brief Private constructor.