}
#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+#include <dali-toolkit/internal/controls/text-controls/text-anchor-impl.h>
+int UtcDaliAccessibilityTextAnchor(void)
+{
+ ToolkitTestApplication application;
+
+ auto textanchor = TextAnchor::New();
+ DALI_TEST_CHECK( textanchor );
+
+ auto textlabel = TextLabel::New();
+ DALI_TEST_CHECK( textlabel );
+
+ Dali::Accessibility::TestEnableSC( true );
+
+ textlabel.Add(textanchor);
+ auto accessible = Dali::Accessibility::Accessible::Get( textanchor );
+ DALI_TEST_CHECK( accessible );
+ auto hyperlink = dynamic_cast< Dali::Accessibility::Hyperlink* >( accessible );
+ DALI_TEST_CHECK( hyperlink );
+ textanchor.SetProperty( Toolkit::TextAnchor::Property::URI, "https://www.tizen.org" );
+ DALI_TEST_EQUALS( hyperlink->IsValid(), true, TEST_LOCATION );
+ auto action = dynamic_cast<Dali::Accessibility::Action*>( accessible );
+ // activation of valid hyperlink
+ DALI_TEST_CHECK( action->DoAction( "accessibilityActivated" ) );
+ // making hyperlink invalid
+ textanchor.SetProperty( Toolkit::TextAnchor::Property::URI, "" );
+ DALI_TEST_EQUALS( hyperlink->IsValid(), false, TEST_LOCATION );
+ DALI_TEST_CHECK( !action->DoAction( "accessibilityActivated" ) );
+
+ Dali::Accessibility::TestEnableSC( false );
+
+ END_TEST;
+}
+
int UtcDaliAccessibilityTextField(void)
{
ToolkitTestApplication application;
DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+ auto hypertext = dynamic_cast< Dali::Accessibility::Hypertext* >( accessible );
+ DALI_TEST_CHECK( hypertext );
+ // text without the anchors markup and ENABLE_MARKUP property set (by default) to false
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set (by default) to false
+ textfield.SetProperty( Toolkit::TextField::Property::TEXT, "12345<a href = 'https://www.tizen.org'>anchor1</a>12345<a href = 'https://www.tizen.org' >veryveryveryveryveryveryveryverylonganchor2</a>12345<a href = 'https://www.tizen.org'>anchor3</a>12345" );
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set to true
+ textfield.SetProperty( Toolkit::TextField::Property::ENABLE_MARKUP, true);
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 3, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), 0, TEST_LOCATION ); //1st anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 17 ), 1, TEST_LOCATION ); //2nd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 66 ), 2, TEST_LOCATION ); //3rd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ auto hyperlink = hypertext->GetLink( 0 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 5, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 12, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorCount(), 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorUri( 0 ), "https://www.tizen.org", TEST_LOCATION );
+ auto anchorAccessible = hyperlink->GetAnchorAccessible( 0 );
+ DALI_TEST_EQUALS( hyperlink == anchorAccessible, true, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 1 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 17, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 60, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 2 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 65, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 72, TEST_LOCATION );
+
Dali::Accessibility::TestEnableSC( false );
END_TEST;
DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+ auto hypertext = dynamic_cast< Dali::Accessibility::Hypertext* >( accessible );
+ DALI_TEST_CHECK( hypertext );
+ // text without the anchors markup and ENABLE_MARKUP property set (by default) to false
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set (by default) to false
+ texteditor.SetProperty( Toolkit::TextEditor::Property::TEXT, "12345<a href = 'https://www.tizen.org'>anchor1</a>12345<a href = 'https://www.tizen.org' >veryveryveryveryveryveryveryverylonganchor2</a>12345<a href = 'https://www.tizen.org'>anchor3</a>12345" );
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set to true
+ texteditor.SetProperty( Toolkit::TextEditor::Property::ENABLE_MARKUP, true);
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 3, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), 0, TEST_LOCATION ); //1st anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 17 ), 1, TEST_LOCATION ); //2nd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 66 ), 2, TEST_LOCATION ); //3rd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ auto hyperlink = hypertext->GetLink( 0 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 5, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 12, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorCount(), 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorUri( 0 ), "https://www.tizen.org", TEST_LOCATION );
+ auto anchorAccessible = hyperlink->GetAnchorAccessible( 0 );
+ DALI_TEST_EQUALS( hyperlink == anchorAccessible, true, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 1 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 17, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 60, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 2 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 65, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 72, TEST_LOCATION );
+
Dali::Accessibility::TestEnableSC( false );
END_TEST;
DALI_TEST_EQUALS( text->SetRangeOfSelection( 1, 0, 1 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION );
+ auto hypertext = dynamic_cast< Dali::Accessibility::Hypertext* >( accessible );
+ DALI_TEST_CHECK( hypertext );
+ // text without the anchors markup and ENABLE_MARKUP property set (by default) to false
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set (by default) to false
+ textlabel.SetProperty( Toolkit::TextLabel::Property::TEXT, "12345<a href = 'https://www.tizen.org'>anchor1</a>12345<a href = 'https://www.tizen.org' >veryveryveryveryveryveryveryverylonganchor2</a>12345<a href = 'https://www.tizen.org'>anchor3</a>12345" );
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 0 ) == nullptr, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLink( 5 ) == nullptr, true, TEST_LOCATION );
+ // text with the anchors markup and ENABLE_MARKUP property set to true
+ textlabel.SetProperty( Toolkit::TextLabel::Property::ENABLE_MARKUP, true);
+ DALI_TEST_EQUALS( hypertext->GetLinkCount(), 3, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( -1 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 0 ), -1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 5 ), 0, TEST_LOCATION ); //1st anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 17 ), 1, TEST_LOCATION ); //2nd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLinkIndex( 66 ), 2, TEST_LOCATION ); //3rd anchor index
+ DALI_TEST_EQUALS( hypertext->GetLink( -1 ) == nullptr, true, TEST_LOCATION );
+ auto hyperlink = hypertext->GetLink( 0 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 5, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 12, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorCount(), 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetAnchorUri( 0 ), "https://www.tizen.org", TEST_LOCATION );
+ auto anchorAccessible = hyperlink->GetAnchorAccessible( 0 );
+ DALI_TEST_EQUALS( hyperlink == anchorAccessible, true, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 1 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 17, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 60, TEST_LOCATION );
+ hyperlink = hypertext->GetLink( 2 );
+ DALI_TEST_CHECK ( hyperlink );
+ DALI_TEST_EQUALS( hyperlink->GetStartIndex(), 65, TEST_LOCATION );
+ DALI_TEST_EQUALS( hyperlink->GetEndIndex(), 72, TEST_LOCATION );
+
Dali::Accessibility::TestEnableSC( false );
END_TEST;
#include <dali-toolkit/dali-toolkit.h>
#include <dali/devel-api/adaptor-framework/accessibility.h>
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
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;
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;
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;
static bool gAnchorClickedCallBackCalled;
static bool gAnchorClickedCallBackNotCalled;
+static bool gTextFitChangedCallBackCalled;
+
struct CallbackFunctor
{
CallbackFunctor(bool* callbackFlag)
}
}
+static void TestTextFitChangedCallback(TextLabel control)
+{
+ tet_infoline(" TestTextFitChangedCallback");
+ gTextFitChangedCallBackCalled = true;
+}
+
bool DaliTestCheckMaps( const Property::Map& mapGet, const Property::Map& mapSet, const std::vector<std::string>& indexConversionTable = std::vector<std::string>() )
{
const Property::Map::SizeType size = mapGet.Count();
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;
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;
END_TEST;
-}
\ No newline at end of file
+}
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"
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=""
#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"
#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"
bool mIsModal = false;
bool mIsRoot = false;
- Dali::Actor Self()
+ Dali::Actor Self() const
{
auto handle = mSelf.GetHandle();
--- /dev/null
+/*
+ * 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 <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-anchor-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+namespace Toolkit
+{
+TextAnchor TextAnchor::New()
+{
+ return Internal::TextAnchor::New();
+}
+
+TextAnchor::TextAnchor()
+{
+}
+
+TextAnchor::TextAnchor(const TextAnchor& handle)
+: Control(handle)
+{
+}
+
+TextAnchor& TextAnchor::operator=(const TextAnchor& handle)
+{
+ if(&handle != this)
+ {
+ Control::operator=(handle);
+ }
+ return *this;
+}
+
+TextAnchor::~TextAnchor()
+{
+}
+
+TextAnchor TextAnchor::DownCast(BaseHandle handle)
+{
+ return Control::DownCast<TextAnchor, Internal::TextAnchor>(handle);
+}
+
+TextAnchor::TextAnchor(Internal::TextAnchor& implementation)
+: Control(implementation)
+{
+}
+
+TextAnchor::TextAnchor(Dali::Internal::CustomActor* internal)
+: Control(internal)
+{
+ VerifyCustomActorPointer<Internal::TextAnchor>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_ANCHOR_DEVEL_H
+#define DALI_TOOLKIT_TEXT_ANCHOR_DEVEL_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 <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class TextAnchor;
+}
+
+/**
+ * @brief A control which renders anchor (hyperlink) in hypertext.
+ */
+class DALI_TOOLKIT_API TextAnchor : public Control
+{
+public:
+ /**
+ * @brief The start and end property ranges for this control.
+ */
+ enum PropertyRange
+ {
+ PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+ PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property indices
+ };
+
+ /**
+ * @brief An enumeration of properties belonging to the TextAnchor class.
+ */
+ struct Property
+ {
+ enum
+ {
+ /**
+ * @brief The index of a character in text at which an anchor starts.
+ * @details Name "startCharacterIndex", type INTEGER.
+ */
+ START_CHARACTER_INDEX = PROPERTY_START_INDEX,
+
+ /**
+ * @brief The index of a character in text that stands one position after the anchor's last character.
+ * @details Name "endCharacterIndex", type INTEGER.
+ */
+ END_CHARACTER_INDEX,
+
+ /**
+ * @brief The URI associated with an anchor.
+ * @details Name "uri", type STRING.
+ */
+ URI
+ };
+ };
+
+ /**
+ * @brief Creates the TextAnchor control.
+ * @return A handle to the TextAnchor control.
+ */
+ static TextAnchor New();
+
+ /**
+ * @brief Creates an empty handle.
+ */
+ TextAnchor();
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @param[in] handle The handle to copy from.
+ */
+ TextAnchor(const TextAnchor& handle);
+
+ /**
+ * @brief Assignment operator.
+ *
+ * @param[in] handle The handle to copy from.
+ * @return A reference to this.
+ */
+ TextAnchor& operator=(const TextAnchor& handle);
+
+ /**
+ * @brief Destructor
+ *
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.
+ */
+ ~TextAnchor();
+
+ /**
+ * @brief Downcast a handle to TextAnchor.
+ *
+ * If the BaseHandle points is a TextAnchor the downcast returns a valid handle.
+ * If not the returned handle is left empty.
+ *
+ * @param[in] handle Handle to an object
+ * @return handle to a TextAnchor or an empty handle
+ */
+ static TextAnchor DownCast(BaseHandle handle);
+
+public: // Not intended for application developers
+ /**
+ * @brief Creates a handle using the Toolkit::Internal implementation.
+ *
+ * @param[in] implementation The Control implementation.
+ */
+ DALI_INTERNAL TextAnchor(Internal::TextAnchor& implementation);
+
+ /**
+ * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+ *
+ * @param[in] internal A pointer to the internal CustomActor.
+ */
+ explicit DALI_INTERNAL TextAnchor(Dali::Internal::CustomActor* internal);
+
+}; // Class TextAnchor
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ANCHOR_DEVEL_H
return GetImpl(textLabel).AnchorClickedSignal();
}
+TextFitChangedSignalType& TextFitChangedSignal(TextLabel textLabel)
+{
+ return GetImpl(textLabel).TextFitChangedSignal();
+}
+
} // namespace DevelTextLabel
} // namespace Toolkit
using AnchorClickedSignalType = Signal<void(TextLabel, const char*, uint32_t)>;
/**
+ * @brief TextFit property changed signal type.
+ */
+using TextFitChangedSignalType = Signal<void(TextLabel)>;
+
+/**
* @brief This signal is emitted when the anchor is clicked.
*
* A callback of the following type may be connected:
*/
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
${devel_api_src_dir}/controls/shadow-view/shadow-view.cpp
${devel_api_src_dir}/controls/super-blur-view/super-blur-view.cpp
${devel_api_src_dir}/controls/table-view/table-view.cpp
+ ${devel_api_src_dir}/controls/text-controls/text-anchor-devel.cpp
${devel_api_src_dir}/controls/text-controls/text-editor-devel.cpp
${devel_api_src_dir}/controls/text-controls/text-field-devel.cpp
${devel_api_src_dir}/controls/text-controls/text-label-devel.cpp
)
SET( devel_api_text_controls_header_files
+ ${devel_api_src_dir}/controls/text-controls/text-anchor-devel.h
${devel_api_src_dir}/controls/text-controls/text-editor-devel.h
${devel_api_src_dir}/controls/text-controls/text-field-devel.h
${devel_api_src_dir}/controls/text-controls/text-label-devel.h
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
+
+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<bool>());
+ break;
+ }
+ case Toolkit::ScrollView::Property::PANNING_ENABLED:
+ {
+ scrollViewImpl.SetScrollSensitive(value.Get<bool>());
+ break;
+ }
+ case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
+ {
+ scrollViewImpl.SetAxisAutoLock(value.Get<bool>());
+ break;
+ }
+ case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+ {
+ scrollViewImpl.SetWheelScrollDistanceStep(value.Get<Vector2>());
+ 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
--- /dev/null
+#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 <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property.h>
+
+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
#include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h>
#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
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
{
mRulerX = ruler;
- UpdatePropertyDomain();
+ ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
mConstraints.UpdateMainInternalConstraint(*this);
}
{
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();
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)
mMaxOvershoot = mUserMaxOvershoot;
}
}
- UpdatePropertyDomain();
+ ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
mConstraints.UpdateMainInternalConstraint(*this);
if(IsOvershootEnabled())
{
}
}
-Vector2 ScrollView::GetOvershoot(Vector2& position) const
-{
- Vector3 size = Self().GetCurrentProperty<Vector3>(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
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<bool>());
- break;
- }
- case Toolkit::ScrollView::Property::PANNING_ENABLED:
- {
- scrollViewImpl.SetScrollSensitive(value.Get<bool>());
- break;
- }
- case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
- {
- scrollViewImpl.SetAxisAutoLock(value.Get<bool>());
- break;
- }
- case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
- {
- scrollViewImpl.SetWheelScrollDistanceStep(value.Get<Vector2>());
- 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)
class ScrollOvershootIndicator;
typedef IntrusivePtr<ScrollOvershootIndicator> ScrollOvershootIndicatorPtr;
+class ScrollViewPropertyHandler;
+
/**
* @copydoc Toolkit::ScrollView
*/
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();
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
*/
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&);
bool mTransientScrollBar : 1; ///< True if scroll-bar should be automatically show/hidden during/after panning
friend ScrollViewConstraints;
+ friend ScrollViewPropertyHandler;
};
/**
#include <dali/public-api/actors/layer.h>
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/internal/text/text-view.h>
namespace Dali::Toolkit::Internal
{
+void CommonTextUtils::SynchronizeTextAnchorsInParent(
+ Actor parent,
+ Text::ControllerPtr controller,
+ std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ for(auto& anchorActor : anchorActors)
+ {
+ parent.Remove(anchorActor);
+ }
+ if(Dali::Accessibility::IsUp())
+ {
+ controller->GetAnchorActors(anchorActors);
+ for(auto& anchorActor : anchorActors)
+ {
+ parent.Add(anchorActor);
+ }
+ }
+}
+
void CommonTextUtils::RenderText(
- Actor textActor,
- Text::RendererPtr renderer,
- Text::ControllerPtr controller,
- Text::DecoratorPtr decorator,
- float& alignmentOffset,
- Actor& renderableActor,
- Actor& backgroundActor,
- Toolkit::Control& stencil,
- std::vector<Actor>& clippingDecorationActors,
- Text::Controller::UpdateTextType updateTextType)
+ Actor textActor,
+ Text::RendererPtr renderer,
+ Text::ControllerPtr controller,
+ Text::DecoratorPtr decorator,
+ float& alignmentOffset,
+ Actor& renderableActor,
+ Actor& backgroundActor,
+ Toolkit::Control& stencil,
+ std::vector<Actor>& clippingDecorationActors,
+ std::vector<Toolkit::TextAnchor>& anchorActors,
+ Text::Controller::UpdateTextType updateTextType)
{
Actor newRenderableActor;
backgroundActor.LowerToBottom();
}
}
+ SynchronizeTextAnchorsInParent(textActor, controller, anchorActors);
}
}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
#include <dali-toolkit/internal/text/rendering/text-renderer.h>
#include <dali-toolkit/internal/text/text-controller.h>
* @param[in,out] backgroundActor Actor for rendering background
* @param[in,out] stencil Clipping actor
* @param[in,out] clippingDecorationActors Clipping decoration actors
+ * @param[in,out] anchorActors Anchor actors
* @param[in] updateTextType How the text has been updated
*/
static void RenderText(
Actor& backgroundActor,
Toolkit::Control& stencil,
std::vector<Actor>& clippingDecorationActors,
+ std::vector<Toolkit::TextAnchor>& anchorActors,
Text::Controller::UpdateTextType updateTextType);
+
+ /**
+ * Common method to synchronize TextAnchor actors with Anchor objects in text's logical model.
+ * @param[in] parent The actor that is a parent of anchor actors
+ * @param[in] controller pointer to the text controller
+ * @param[in,out] anchorActors Anchor actors
+ */
+ static void SynchronizeTextAnchorsInParent(
+ Actor parent,
+ Text::ControllerPtr controller,
+ std::vector<Toolkit::TextAnchor>& anchorActors);
};
} // namespace Dali::Toolkit::Internal
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/controls/text-controls/text-anchor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+
+// DEVEL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+using namespace Dali::Toolkit::Text;
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+// Type registration
+BaseHandle Create()
+{
+ return Toolkit::TextAnchor::New();
+}
+
+// clang-format off
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextAnchor, Toolkit::Control, Create);
+
+DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "startCharacterIndex", INTEGER, START_CHARACTER_INDEX)
+DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "endCharacterIndex", INTEGER, END_CHARACTER_INDEX )
+DALI_PROPERTY_REGISTRATION(Toolkit, TextAnchor, "uri", STRING, URI )
+
+DALI_TYPE_REGISTRATION_END()
+// clang-format on
+
+} // namespace
+
+Toolkit::TextAnchor TextAnchor::New()
+{
+ // Create the implementation, temporarily owned by this handle on stack
+ IntrusivePtr<TextAnchor> impl = new TextAnchor();
+
+ // Pass ownership to CustomActor handle
+ Toolkit::TextAnchor handle(*impl);
+
+ // Second-phase init of the implementation
+ // This can only be done after the CustomActor connection has been made...
+ impl->Initialize();
+
+ return handle;
+}
+
+Property::Value TextAnchor::GetProperty(BaseObject* object, Property::Index index)
+{
+ Property::Value value;
+
+ Toolkit::TextAnchor anchor = Toolkit::TextAnchor::DownCast(Dali::BaseHandle(object));
+
+ if(anchor)
+ {
+ TextAnchor& impl(GetImpl(anchor));
+
+ switch(index)
+ {
+ case Toolkit::TextAnchor::Property::START_CHARACTER_INDEX:
+ {
+ value = impl.mStartCharacterIndex;
+ break;
+ }
+ case Toolkit::TextAnchor::Property::END_CHARACTER_INDEX:
+ {
+ value = impl.mEndCharacterIndex;
+ break;
+ }
+ case Toolkit::TextAnchor::Property::URI:
+ {
+ value = impl.mUri;
+ break;
+ }
+ }
+ }
+
+ return value;
+}
+
+void TextAnchor::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
+{
+ Toolkit::TextAnchor anchor = Toolkit::TextAnchor::DownCast(Dali::BaseHandle(object));
+
+ if(anchor)
+ {
+ TextAnchor& impl(GetImpl(anchor));
+ switch(index)
+ {
+ case Toolkit::TextAnchor::Property::START_CHARACTER_INDEX:
+ {
+ value.Get(impl.mStartCharacterIndex);
+ break;
+ }
+
+ case Toolkit::TextAnchor::Property::END_CHARACTER_INDEX:
+ {
+ value.Get(impl.mEndCharacterIndex);
+ break;
+ }
+
+ case Toolkit::TextAnchor::Property::URI:
+ {
+ value.Get(impl.mUri);
+ break;
+ }
+ }
+ }
+}
+
+void TextAnchor::OnInitialize()
+{
+ Actor self = Self();
+
+ // Enable highlightability
+ self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
+
+ DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
+ return std::unique_ptr<Dali::Accessibility::Accessible>(
+ new AccessibleImpl(actor, Dali::Accessibility::Role::LINK));
+ });
+}
+
+TextAnchor::TextAnchor()
+: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))
+{
+}
+
+TextAnchor::~TextAnchor()
+{
+}
+
+int32_t TextAnchor::AccessibleImpl::GetEndIndex() const
+{
+ auto self = Toolkit::TextAnchor::DownCast(Self());
+ return self.GetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX).Get<int>();
+}
+
+int32_t TextAnchor::AccessibleImpl::GetStartIndex() const
+{
+ auto self = Toolkit::TextAnchor::DownCast(Self());
+ return self.GetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX).Get<int>();
+}
+
+int32_t TextAnchor::AccessibleImpl::GetAnchorCount() const
+{
+ return 1;
+}
+
+Dali::Accessibility::Accessible* TextAnchor::AccessibleImpl::GetAnchorAccessible(int32_t anchorIndex) const
+{
+ return Control::Impl::GetAccessibilityObject(Self());
+}
+
+std::string TextAnchor::AccessibleImpl::GetAnchorUri(int32_t anchorIndex) const
+{
+ auto self = Toolkit::TextAnchor::DownCast(Self());
+ return self.GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
+}
+
+bool TextAnchor::AccessibleImpl::IsValid() const
+{
+ return !GetAnchorUri(0).empty();
+}
+
+bool TextAnchor::OnAccessibilityActivated()
+{
+ auto uri = Self().GetProperty(Toolkit::TextAnchor::Property::URI).Get<std::string>();
+ if(!uri.empty())
+ {
+ Dali::Actor current = Self();
+ Dali::Toolkit::Text::AnchorControlInterface* parentImplementationAnchorInterface = nullptr;
+ while(!current.GetProperty<bool>(Actor::Property::IS_ROOT) && !parentImplementationAnchorInterface)
+ {
+ Dali::Actor parentAsActor = current.GetParent();
+ Dali::CustomActor parentAsCustomActor = Dali::CustomActor::DownCast(parentAsActor);
+ Dali::CustomActorImpl& parentImplementation = parentAsCustomActor.GetImplementation();
+ parentImplementationAnchorInterface = dynamic_cast<Dali::Toolkit::Text::AnchorControlInterface*>(&parentImplementation);
+ current = parentAsActor;
+ }
+ if(parentImplementationAnchorInterface)
+ {
+ parentImplementationAnchorInterface->AnchorClicked(uri);
+ return true;
+ }
+ else
+ {
+ DALI_LOG_ERROR("TextAnchor::OnAccessibilityActivate cannot find ancestor actor implementing Dali::Toolkit::Text::AnchorControlInterface.\n");
+ }
+ }
+ return false;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_ANCHOR_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_ANCHOR_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 <dali-toolkit/public-api/controls/control-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * @brief A control which renders anchor (hyperlink) in hypertext.
+ */
+class TextAnchor : public Control
+{
+public:
+ /**
+ * @copydoc Dali::Toollkit::TextAnchor::New()
+ */
+ static Toolkit::TextAnchor New();
+
+ // Properties
+
+ /**
+ * @brief Called when a property of an object of this type is set.
+ *
+ * @param[in] object The object whose property is set.
+ * @param[in] index The property index.
+ * @param[in] value The new property value.
+ */
+ static void SetProperty(BaseObject* object, Property::Index index, const Property::Value& value);
+
+ /**
+ * @brief Called to retrieve a property of an object of this type.
+ *
+ * @param[in] object The object whose property is to be retrieved.
+ * @param[in] index The property index.
+ * @return The current value of the property.
+ */
+ static Property::Value GetProperty(BaseObject* object, Property::Index index);
+
+private: // From Control
+ /**
+ * @copydoc Control::OnInitialize()
+ */
+ void OnInitialize() override;
+
+ /**
+ * @copydoc Control::OnPropertySet()
+ */
+ // void OnPropertySet(Property::Index index, const Property::Value& propertyValue) override;
+
+ /**
+ * @copydoc Control::OnAccessibilityActivated()
+ */
+ bool OnAccessibilityActivated() override;
+
+private: // Implementation
+ /**
+ * Construct a new TextAnchor.
+ */
+ TextAnchor();
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~TextAnchor();
+
+private:
+ // Undefined copy constructor and assignment operators
+ TextAnchor(const TextAnchor&);
+ TextAnchor& operator=(const TextAnchor& rhs);
+
+ //Data
+ int mStartCharacterIndex;
+ int mEndCharacterIndex;
+ std::string mUri;
+
+protected:
+ /**
+ * @brief This structure is to connect TextAnchor with Accessible functions.
+ */
+ struct AccessibleImpl : public DevelControl::AccessibleImpl,
+ public virtual Dali::Accessibility::Hyperlink
+ {
+ using DevelControl::AccessibleImpl::AccessibleImpl;
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::GetEndIndex()
+ */
+ int32_t GetEndIndex() const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::GetStartIndex()
+ */
+ int32_t GetStartIndex() const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::GetAnchorCount()
+ */
+ int32_t GetAnchorCount() const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::GetAnchorAccessible()
+ */
+ Accessible* GetAnchorAccessible(int32_t anchorIndex) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::GetAnchorUri()
+ */
+ std::string GetAnchorUri(int32_t anchorIndex) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hyperlink::IsValid()
+ */
+ bool IsValid() const override;
+ };
+};
+
+inline Toolkit::Internal::TextAnchor& GetImpl(Toolkit::TextAnchor& textAnchor)
+{
+ DALI_ASSERT_ALWAYS(textAnchor);
+
+ Dali::RefObject& handle = textAnchor.GetImplementation();
+
+ return static_cast<Toolkit::Internal::TextAnchor&>(handle);
+}
+
+inline const Toolkit::Internal::TextAnchor& GetImpl(const Toolkit::TextAnchor& textAnchor)
+{
+ DALI_ASSERT_ALWAYS(textAnchor);
+
+ const Dali::RefObject& handle = textAnchor.GetImplementation();
+
+ return static_cast<const Toolkit::Internal::TextAnchor&>(handle);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_ANCHOR_H
return mScrollStateChangedSignal;
}
+void TextEditor::OnAccessibilityStatusChanged()
+{
+ CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+}
+
void TextEditor::OnInitialize()
{
Actor self = Self();
return std::unique_ptr<Dali::Accessibility::Accessible>(
new AccessibleImpl(actor, Dali::Accessibility::Role::ENTRY));
});
+
+ Accessibility::Bridge::EnabledSignal().Connect(this, &TextEditor::OnAccessibilityStatusChanged);
+ Accessibility::Bridge::DisabledSignal().Connect(this, &TextEditor::OnAccessibilityStatusChanged);
}
void TextEditor::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
{
- CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, updateTextType);
+ CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
if(mRenderableActor)
{
ApplyScrollPosition();
return true;
}
+int32_t TextEditor::AccessibleImpl::GetLinkCount() const
+{
+ auto self = Toolkit::TextEditor::DownCast(Self());
+ return Dali::Toolkit::GetImpl(self).mAnchorActors.size();
+}
+
+Accessibility::Hyperlink* TextEditor::AccessibleImpl::GetLink(int32_t linkIndex) const
+{
+ if(linkIndex < 0 || linkIndex >= GetLinkCount())
+ {
+ return nullptr;
+ }
+ auto self = Toolkit::TextEditor::DownCast(Self());
+ auto anchorActor = Dali::Toolkit::GetImpl(self).mAnchorActors[linkIndex];
+ return dynamic_cast<Accessibility::Hyperlink*>(Dali::Accessibility::Accessible::Get(anchorActor));
+}
+
+int32_t TextEditor::AccessibleImpl::GetLinkIndex(int32_t characterOffset) const
+{
+ auto self = Toolkit::TextEditor::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ return controller->GetAnchorIndex(static_cast<size_t>(characterOffset));
+}
+
} // namespace Internal
} // namespace Toolkit
// Connection needed to re-render text, when a text editor returns to the scene.
void OnSceneConnect(Dali::Actor actor);
+ // Needed to synchronize TextAnchor actors with Anchor objects in text's logical model
+ void OnAccessibilityStatusChanged();
+
private: // Data
// Signals
Toolkit::TextEditor::TextChangedSignalType mTextChangedSignal;
Toolkit::DevelTextEditor::SelectionChangedSignalType mSelectionChangedSignal;
Toolkit::DevelTextEditor::SelectionClearedSignalType mSelectionClearedSignal;
- InputMethodContext mInputMethodContext;
- Text::ControllerPtr mController;
- Text::RendererPtr mRenderer;
- Text::DecoratorPtr mDecorator;
- Text::TextVerticalScrollerPtr mTextVerticalScroller;
- Toolkit::Control mStencil;
- Toolkit::ScrollBar mScrollBar;
- Dali::Animation mAnimation; ///< Scroll indicator Show/Hide Animation.
- Dali::TimePeriod mAnimationPeriod;
- std::vector<Actor> mClippingDecorationActors; ///< Decoration actors which need clipping.
- Dali::InputMethodOptions mInputMethodOptions;
+ InputMethodContext mInputMethodContext;
+ Text::ControllerPtr mController;
+ Text::RendererPtr mRenderer;
+ Text::DecoratorPtr mDecorator;
+ Text::TextVerticalScrollerPtr mTextVerticalScroller;
+ Toolkit::Control mStencil;
+ Toolkit::ScrollBar mScrollBar;
+ Dali::Animation mAnimation; ///< Scroll indicator Show/Hide Animation.
+ Dali::TimePeriod mAnimationPeriod;
+ std::vector<Actor> mClippingDecorationActors; ///< Decoration actors which need clipping.
+ std::vector<Toolkit::TextAnchor> mAnchorActors;
+ Dali::InputMethodOptions mInputMethodOptions;
Actor mRenderableActor;
Actor mActiveLayer;
*/
struct AccessibleImpl : public DevelControl::AccessibleImpl,
public virtual Dali::Accessibility::Text,
- public virtual Dali::Accessibility::EditableText
+ public virtual Dali::Accessibility::EditableText,
+ public virtual Dali::Accessibility::Hypertext
{
using DevelControl::AccessibleImpl::AccessibleImpl;
* @copydoc Dali::Accessibility::EditableText::DeleteText()
*/
bool DeleteText(size_t startPosition, size_t endPosition) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLink()
+ */
+ Accessibility::Hyperlink* GetLink(int32_t linkIndex) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkIndex()
+ */
+ int32_t GetLinkIndex(int32_t characterOffset) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkCount()
+ */
+ int32_t GetLinkCount() const override;
};
};
*/
#include <dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
impl.mController->SetMarkupProcessorEnabled(enableMarkup);
+ CommonTextUtils::SynchronizeTextAnchorsInParent(textEditor, impl.mController, impl.mAnchorActors);
break;
}
case Toolkit::TextEditor::Property::INPUT_COLOR:
return fieldInputStyleMask;
}
+bool IsHiddenInput(Toolkit::TextField textField)
+{
+ Property::Map hiddenInputSettings = textField.GetProperty<Property::Map>(Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS);
+ auto mode = hiddenInputSettings.Find(Toolkit::HiddenInput::Property::MODE);
+ if (mode && (mode->Get<int>() != Toolkit::HiddenInput::Mode::HIDE_NONE))
+ {
+ return true;
+ }
+ return false;
+}
+
+char GetSubstituteCharacter(Toolkit::TextField textField)
+{
+ Property::Map hiddenInputSettings = textField.GetProperty<Property::Map>(Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS);
+ auto substChar = hiddenInputSettings.Find(Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER);
+ if (substChar)
+ {
+ return static_cast<char>(substChar->Get<int>());
+ }
+ return STAR;
+}
+
} // namespace
Toolkit::TextField TextField::New()
return mSelectionClearedSignal;
}
+void TextField::OnAccessibilityStatusChanged()
+{
+ CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+}
+
void TextField::OnInitialize()
{
Actor self = Self();
return std::unique_ptr<Dali::Accessibility::Accessible>(
new AccessibleImpl(actor, Dali::Accessibility::Role::ENTRY));
});
+
+ Accessibility::Bridge::EnabledSignal().Connect(this, &TextField::OnAccessibilityStatusChanged);
+ Accessibility::Bridge::DisabledSignal().Connect(this, &TextField::OnAccessibilityStatusChanged);
}
void TextField::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
void TextField::RenderText(Text::Controller::UpdateTextType updateTextType)
{
- CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, updateTextType);
+ CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
}
void TextField::OnKeyInputFocusGained()
std::string TextField::AccessibleImpl::GetName()
{
auto self = Toolkit::TextField::DownCast(Self());
+ if (IsHiddenInput(self))
+ {
+ return {};
+ }
+
return self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
}
{
return {};
}
-
+ if(IsHiddenInput(self))
+ {
+ return std::string(endOffset - startOffset, GetSubstituteCharacter(self));
+ }
return text.substr(startOffset, endOffset - startOffset);
}
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<std::string>();
auto textSize = text.size();
- auto range = Dali::Accessibility::Range{};
-
switch(boundary)
{
case Dali::Accessibility::TextBoundary::CHARACTER:
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<size_t>(indices.first), static_cast<size_t>(indices.second), value};
+ auto startOffset = static_cast<size_t>(indices.first);
+ auto endOffset = static_cast<size_t>(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)
return true;
}
+int32_t TextField::AccessibleImpl::GetLinkCount() const
+{
+ auto self = Toolkit::TextField::DownCast(Self());
+ return Dali::Toolkit::GetImpl(self).mAnchorActors.size();
+}
+
+Accessibility::Hyperlink* TextField::AccessibleImpl::GetLink(int32_t linkIndex) const
+{
+ if(linkIndex < 0 || linkIndex >= GetLinkCount())
+ {
+ return nullptr;
+ }
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto anchorActor = Dali::Toolkit::GetImpl(self).mAnchorActors[linkIndex];
+ return dynamic_cast<Accessibility::Hyperlink*>(Dali::Accessibility::Accessible::Get(anchorActor));
+}
+
+int32_t TextField::AccessibleImpl::GetLinkIndex(int32_t characterOffset) const
+{
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ return controller->GetAnchorIndex(static_cast<size_t>(characterOffset));
+}
+
} // namespace Internal
} // namespace Toolkit
// Connection needed to re-render text, when a Text Field returns to the scene.
void OnSceneConnect(Dali::Actor actor);
+ // Needed to synchronize TextAnchor actors with Anchor objects in text's logical model
+ void OnAccessibilityStatusChanged();
+
private: // Data
// Signals
Toolkit::TextField::TextChangedSignalType mTextChangedSignal;
Toolkit::DevelTextField::SelectionChangedSignalType mSelectionChangedSignal;
Toolkit::DevelTextField::SelectionClearedSignalType mSelectionClearedSignal;
- InputMethodContext mInputMethodContext;
- Text::ControllerPtr mController;
- Text::RendererPtr mRenderer;
- Text::DecoratorPtr mDecorator;
- Toolkit::Control mStencil; ///< For EXCEED_POLICY_CLIP
- std::vector<Actor> mClippingDecorationActors; ///< Decoration actors which need clipping.
- Dali::InputMethodOptions mInputMethodOptions;
+ InputMethodContext mInputMethodContext;
+ Text::ControllerPtr mController;
+ Text::RendererPtr mRenderer;
+ Text::DecoratorPtr mDecorator;
+ Toolkit::Control mStencil; ///< For EXCEED_POLICY_CLIP
+ std::vector<Actor> mClippingDecorationActors; ///< Decoration actors which need clipping.
+ std::vector<Toolkit::TextAnchor> mAnchorActors;
+ Dali::InputMethodOptions mInputMethodOptions;
Actor mRenderableActor;
Actor mActiveLayer;
*/
struct AccessibleImpl : public DevelControl::AccessibleImpl,
public virtual Dali::Accessibility::Text,
- public virtual Dali::Accessibility::EditableText
+ public virtual Dali::Accessibility::EditableText,
+ public virtual Dali::Accessibility::Hypertext
{
using DevelControl::AccessibleImpl::AccessibleImpl;
* @copydoc Dali::Accessibility::EditableText::DeleteText()
*/
bool DeleteText(size_t startPosition, size_t endPosition) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLink()
+ */
+ Accessibility::Hyperlink* GetLink(int32_t linkIndex) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkIndex()
+ */
+ int32_t GetLinkIndex(int32_t characterOffset) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkCount()
+ */
+ int32_t GetLinkCount() const override;
};
};
*/
#include <dali-toolkit/internal/controls/text-controls/text-field-property-handler.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
#include <dali-toolkit/devel-api/text/rendering-backend.h>
DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
impl.mController->SetMarkupProcessorEnabled(enableMarkup);
+ CommonTextUtils::SynchronizeTextAnchorsInParent(textField, impl.mController, impl.mAnchorActors);
break;
}
case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
if(map)
{
impl.mController->SetHiddenInputOption(*map);
+ auto mode = map->Find(Toolkit::HiddenInput::Property::MODE);
+ if(mode && (mode->Get<int>() != 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;
}
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/text-font-style.h>
#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
#include <dali-toolkit/public-api/text/text-enumerations.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
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)
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
case Toolkit::DevelTextLabel::Property::TEXT_FIT:
{
ParseTextFitProperty(impl.mController, value.GetMap());
+ impl.mController->SetTextFitChanged(true);
break;
}
case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
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;
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
return mAnchorClickedSignal;
}
+DevelTextLabel::TextFitChangedSignalType& TextLabel::TextFitChangedSignal()
+{
+ return mTextFitChangedSignal;
+}
+
void TextLabel::OnInitialize()
{
Actor self = Self();
return std::unique_ptr<Dali::Accessibility::Accessible>(
new AccessibleImpl(actor, Dali::Accessibility::Role::LABEL));
});
+
+ Accessibility::Bridge::EnabledSignal().Connect(this, &TextLabel::OnAccessibilityStatusChanged);
+ Accessibility::Bridge::DisabledSignal().Connect(this, &TextLabel::OnAccessibilityStatusChanged);
}
void TextLabel::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
}
break;
}
+ case Toolkit::TextLabel::Property::TEXT:
+ case Toolkit::TextLabel::Property::ENABLE_MARKUP:
+ {
+ CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+ break;
+ }
default:
{
Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
mTextUpdateNeeded = false;
}
+
+ if(mController->IsTextFitChanged())
+ {
+ EmitTextFitChangedSignal();
+ mController->SetTextFitChanged(false);
+ }
}
void TextLabel::RequestTextRelayout()
mController->ChangedLayoutDirection();
}
+void TextLabel::EmitTextFitChangedSignal()
+{
+ Dali::Toolkit::TextLabel handle(GetOwner());
+ mTextFitChangedSignal.Emit(handle);
+}
+
+void TextLabel::OnAccessibilityStatusChanged()
+{
+ CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+}
+
TextLabel::TextLabel()
: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
mRenderingBackend(DEFAULT_RENDERING_BACKEND),
Dali::Accessibility::Range TextLabel::AccessibleImpl::GetTextAtOffset(size_t offset, Dali::Accessibility::TextBoundary boundary)
{
- auto self = Toolkit::TextLabel::DownCast(Self());
- auto text = self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
+ auto self = Toolkit::TextLabel::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
auto textSize = text.size();
auto range = Dali::Accessibility::Range{};
case Dali::Accessibility::TextBoundary::LINE:
{
auto textString = text.c_str();
- auto breaks = std::vector<char>(textSize, 0);
+ auto breaks = std::vector<char>(textSize, 0);
if(boundary == Dali::Accessibility::TextBoundary::WORD)
{
Accessibility::Accessible::FindLineSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
}
- auto index = 0u;
+ auto index = 0u;
auto counter = 0u;
while(index < textSize && counter <= offset)
{
return {};
}
- auto self = Toolkit::TextLabel::DownCast(Self());
- auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ auto self = Toolkit::TextLabel::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
std::string value{};
controller->RetrieveSelection(value);
auto indices = controller->GetSelectionIndexes();
return true;
}
+int32_t TextLabel::AccessibleImpl::GetLinkCount() const
+{
+ auto self = Toolkit::TextLabel::DownCast(Self());
+ return Dali::Toolkit::GetImpl(self).mAnchorActors.size();
+}
+
+Accessibility::Hyperlink* TextLabel::AccessibleImpl::GetLink(int32_t linkIndex) const
+{
+ if(linkIndex < 0 || linkIndex >= GetLinkCount())
+ {
+ return nullptr;
+ }
+ auto self = Toolkit::TextLabel::DownCast(Self());
+ auto anchorActor = Dali::Toolkit::GetImpl(self).mAnchorActors[linkIndex];
+ return dynamic_cast<Accessibility::Hyperlink*>(Dali::Accessibility::Accessible::Get(anchorActor));
+}
+
+int32_t TextLabel::AccessibleImpl::GetLinkIndex(int32_t characterOffset) const
+{
+ auto self = Toolkit::TextLabel::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ return controller->GetAnchorIndex(static_cast<size_t>(characterOffset));
+}
+
} // namespace Internal
} // namespace Toolkit
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.
*/
void OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type);
+ /**
+ * @brief Emits TextFitChanged signal.
+ */
+ void EmitTextFitChangedSignal();
+ void OnAccessibilityStatusChanged();
+
private: // Data
Text::ControllerPtr mController;
Text::TextScrollerPtr mTextScroller;
Toolkit::Visual::Base mVisual;
+ std::vector<Toolkit::TextAnchor> mAnchorActors;
+
// Signals
Toolkit::DevelTextLabel::AnchorClickedSignalType mAnchorClickedSignal;
+ Toolkit::DevelTextLabel::TextFitChangedSignalType mTextFitChangedSignal;
int mRenderingBackend;
bool mTextUpdateNeeded : 1;
* @brief This structure is to connect TextLabel with Accessible functions.
*/
struct AccessibleImpl : public DevelControl::AccessibleImpl,
- public virtual Dali::Accessibility::Text
+ public virtual Dali::Accessibility::Text,
+ public virtual Dali::Accessibility::Hypertext
{
using DevelControl::AccessibleImpl::AccessibleImpl;
* @copydoc Dali::Accessibility::Text::GetNamePropertyIndex()
*/
Property::Index GetNamePropertyIndex() override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLink()
+ */
+ Accessibility::Hyperlink* GetLink(int32_t linkIndex) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkIndex()
+ */
+ int32_t GetLinkIndex(int32_t characterOffset) const override;
+
+ /**
+ * @copydoc Dali::Accessibility::Hypertext::GetLinkCount()
+ */
+ int32_t GetLinkCount() const override;
};
};
${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
${toolkit_src_dir}/controls/super-blur-view/super-blur-view-impl.cpp
${toolkit_src_dir}/controls/table-view/table-view-impl.cpp
${toolkit_src_dir}/controls/text-controls/common-text-utils.cpp
+ ${toolkit_src_dir}/controls/text-controls/text-anchor-impl.cpp
${toolkit_src_dir}/controls/text-controls/text-editor-impl.cpp
${toolkit_src_dir}/controls/text-controls/text-editor-property-handler.cpp
${toolkit_src_dir}/controls/text-controls/text-field-impl.cpp
${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
if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
{
OUT_COLOR = targetColor;
- return;
}
- PreprocessPotential();
+ else
+ {
+ PreprocessPotential();
#endif
#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
- targetColor = convertBorderlineColor(targetColor);
+ targetColor = convertBorderlineColor(targetColor);
#endif
- OUT_COLOR = targetColor;
+ OUT_COLOR = targetColor;
#if IS_REQUIRED_BLUR
- mediump float opacity = calculateBlurOpacity();
- OUT_COLOR.a *= opacity;
+ mediump float opacity = calculateBlurOpacity();
+ OUT_COLOR.a *= opacity;
#elif IS_REQUIRED_ROUNDED_CORNER
- mediump float opacity = calculateCornerOpacity();
- OUT_COLOR.a *= opacity;
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR.a *= opacity;
+#endif
+
+#if IS_REQUIRED_BLUR || IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ }
#endif
}
if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
{
OUT_COLOR = textureColor;
- return;
}
- PreprocessPotential();
+ else
+ {
+ PreprocessPotential();
#endif
#if IS_REQUIRED_BORDERLINE
- textureColor = convertBorderlineColor(textureColor);
+ textureColor = convertBorderlineColor(textureColor);
#endif
- OUT_COLOR = textureColor;
+ OUT_COLOR = textureColor;
#if IS_REQUIRED_ROUNDED_CORNER
- mediump float opacity = calculateCornerOpacity();
- OUT_COLOR *= opacity;
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR *= opacity;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ }
#endif
}
if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
{
OUT_COLOR = textureColor;
- return;
}
- PreprocessPotential();
+ else
+ {
+ PreprocessPotential();
#endif
#if IS_REQUIRED_BORDERLINE
- textureColor = convertBorderlineColor(textureColor);
+ textureColor = convertBorderlineColor(textureColor);
#endif
- OUT_COLOR = textureColor;
+ OUT_COLOR = textureColor;
#if IS_REQUIRED_ROUNDED_CORNER
- mediump float opacity = calculateCornerOpacity();
- OUT_COLOR.a *= opacity;
- OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
+ mediump float opacity = calculateCornerOpacity();
+ OUT_COLOR.a *= opacity;
+ OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+ }
#endif
}
using namespace Dali::Toolkit;
-const uint32_t STAR = 0x2A; // Set default substitute character as '*'
const int DEFAULT_SHOW_DURATION = 1000;
namespace Dali
{
namespace Text
{
+
+static constexpr const uint32_t STAR = 0x2A; // Set default substitute character as '*'
+
/**
* Class to handle the hidden text
*/
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+
+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<BidirectionalLineInfoRun>::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<BidirectionalLineInfoRun>::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<GlyphIndex>::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<CharacterIndex>::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
--- /dev/null
+#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 <dali-toolkit/internal/text/text-controller.h>
+
+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
#include <dali-toolkit/internal/text/text-controller-impl.h>
// EXTERNAL INCLUDES
+#include <cmath>
#include <dali/integration-api/debug.h>
#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
#include <dali-toolkit/internal/text/text-editable-control-interface.h>
}
}
}
+
+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)
}
}
+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<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ }
+ else
+ {
+ return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ }
+}
+
void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
{
mTextUpdateInfo.mParagraphCharacterIndex = 0u;
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<BidirectionalLineInfoRun>::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<BidirectionalLineInfoRun>::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<GlyphIndex>::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<CharacterIndex>::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)
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)
}
}
+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)
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,
return mEventData ? -mModel->mScrollPosition.y : 0.0f;
}
+Vector3 Controller::Impl::GetAnchorPosition(Anchor anchor) const
+{
+ //TODO
+ return Vector3(10.f, 10.f, 10.f);
+}
+
+Vector2 Controller::Impl::GetAnchorSize(Anchor anchor) const
+{
+ //TODO
+ return Vector2(10.f, 10.f);
+}
+
+Toolkit::TextAnchor Controller::Impl::CreateAnchorActor(Anchor anchor)
+{
+ auto actor = Toolkit::TextAnchor::New();
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ const Vector3 anchorPosition = GetAnchorPosition(anchor);
+ actor.SetProperty(Actor::Property::POSITION, anchorPosition);
+ const Vector2 anchorSize = GetAnchorSize(anchor);
+ actor.SetProperty(Actor::Property::SIZE, anchorSize);
+ std::string anchorText(mModel->mLogicalModel->mText.Begin() + anchor.startIndex, mModel->mLogicalModel->mText.Begin() + anchor.endIndex);
+ actor.SetProperty(Actor::Property::NAME, anchorText);
+ actor.SetProperty(Toolkit::TextAnchor::Property::URI, std::string(anchor.href));
+ actor.SetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX, static_cast<int>(anchor.startIndex));
+ actor.SetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX, static_cast<int>(anchor.endIndex));
+ return actor;
+}
+
+void Controller::Impl::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ /* TODO: Now actors are created/destroyed in every "RenderText" function call. Even when we add just 1 character,
+ we need to create and destroy potentially many actors. Some optimization can be considered here.
+ Maybe a "dirty" flag in mLogicalModel? */
+ anchorActors.clear();
+ for(auto& anchor : mModel->mLogicalModel->mAnchors)
+ {
+ auto actor = CreateAnchorActor(anchor);
+ anchorActors.push_back(actor);
+ }
+}
+
+int32_t Controller::Impl::GetAnchorIndex(size_t characterOffset) const
+{
+ Vector<Anchor>::Iterator it = mModel->mLogicalModel->mAnchors.Begin();
+
+ while(it != mModel->mLogicalModel->mAnchors.End() && (it->startIndex > characterOffset || it->endIndex <= characterOffset))
+ {
+ it++;
+ }
+
+ return it == mModel->mLogicalModel->mAnchors.End() ? -1 : it - mModel->mLogicalModel->mAnchors.Begin();
+}
+
void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
{
//Underlined character runs for markup-processor
}
}
+void Controller::Impl::SetAutoScrollEnabled(bool enable)
+{
+ if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
+ {
+ mOperationsPending = static_cast<OperationsMask>(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<OperationsMask>(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<OperationsMask>(LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ ALIGN |
+ REORDER);
+
+ mTextUpdateInfo.mFullRelayoutNeeded = true;
+ mOperationsPending = static_cast<OperationsMask>(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<OperationsMask>(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<OperationsMask>(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<OperationsMask>(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<OperationsMask>(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<OperationsMask>(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<OperationsMask>(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
}
/**
+ * @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.
*
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.
float GetDefaultFontLineHeight();
/**
+ * @copydoc Controller::SetDefaultLineSpacing
+ */
+ bool SetDefaultLineSpacing(float lineSpacing);
+
+ /**
+ * @copydoc Controller::SetDefaultLineSize
+ */
+ bool SetDefaultLineSize(float lineSize);
+
+ /**
* @copydoc Text::Controller::GetPrimaryCursorPosition()
*/
CharacterIndex GetPrimaryCursorPosition() const;
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.
*/
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();
+
+ /**
+ * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
+ *
+ * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
+ */
+ void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
+
+ /**
+ * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
+ *
+ * @param[in] characterOffset A position in text coords.
+ *
+ * @return the 0-based index in anchor vector (-1 if an anchor not found)
+ */
+ int32_t GetAnchorIndex(size_t characterOffset) const;
+
+ /**
+ * @brief Return the geometrical position of an anchor relative to the parent origin point.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The x, y, z coordinates of an anchor.
+ */
+ Vector3 GetAnchorPosition(Anchor anchor) const;
+
+ /**
+ * @brief Return the size of an anchor expresed as a vector containing anchor's width and height.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The width and height of an anchor.
+ */
+ Vector2 GetAnchorSize(Anchor anchor) const;
+
+ /**
+ * @brief Return the actor representing an anchor.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The actor representing an anchor.
+ */
+ Toolkit::TextAnchor CreateAnchorActor(Anchor anchor);
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.
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<OperationsMask>(CONVERT_TO_UTF32 |
float minPointSize = impl.mTextFitMinSize;
float maxPointSize = impl.mTextFitMaxSize;
float pointInterval = impl.mTextFitStepSize;
+ float currentFitPointSize = impl.mFontDefaults->mFitPointSize;
model->mElideEnabled = false;
Vector<float> pointSizeArray;
}
model->mElideEnabled = actualellipsis;
+ if(currentFitPointSize != pointSizeArray[bestSizeIndex])
+ {
+ impl.mTextFitChanged = true;
+ }
impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
impl.mFontDefaults->sizeDefined = true;
- controller.ClearFontData();
+ impl.ClearFontData();
}
}
// Reset the scroll position in inactive state
if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE))
{
- controller.ResetScrollPosition();
+ impl.ResetScrollPosition();
}
}
ResetText(controller);
// Remove the style.
- controller.ClearStyleData();
+ impl.ClearStyleData();
CharacterIndex lastCursorIndex = 0u;
controller.ResetCursorPosition(lastCursorIndex);
// Scrolls the text to make the cursor visible.
- controller.ResetScrollPosition();
+ impl.ResetScrollPosition();
impl.RequestRelayout();
mImpl->mMetrics->SetGlyphType(glyphType);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
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<OperationsMask>(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<OperationsMask>(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;
}
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
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<OperationsMask>(LAYOUT |
- UPDATE_LAYOUT_SIZE |
- ALIGN |
- REORDER);
-
- mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
- mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | layoutOperations);
-
- // Need to recalculate natural size
- mImpl->mRecalculateNaturalSize = true;
-
- mImpl->RequestRelayout();
- }
+ mImpl->SetMultiLineEnabled(enable);
}
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<OperationsMask>(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
void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
{
- if(alignment != mImpl->mModel->mVerticalAlignment)
- {
- // Set the alignment.
- mImpl->mModel->mVerticalAlignment = alignment;
- mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
- mImpl->RequestRelayout();
- }
+ mImpl->SetVerticalAlignment(alignment);
}
VerticalAlignment::Type Controller::GetVerticalAlignment() const
void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
{
- if(lineWrapMode != mImpl->mModel->mLineWrapMode)
- {
- // Update Text layout for applying wrap mode
- mImpl->mOperationsPending = static_cast<OperationsMask>(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<OperationsMask>(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
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);
return mImpl->mTextFitContentSize;
}
+float Controller::GetTextFitPointSize() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f;
+}
+
void Controller::SetPlaceholderTextElideEnabled(bool enabled)
{
PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
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
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
UpdateCursorPosition(mImpl->mEventData);
// Clear the font-specific data
- ClearFontData();
+ mImpl->ClearFontData();
mImpl->RequestRelayout();
}
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<OperationsMask>(mImpl->mOperationsPending | COLOR);
- mImpl->RequestRelayout();
- }
+ mImpl->SetDefaultColor(color);
}
const Vector4& Controller::GetDefaultColor() 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
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
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<OperationsMask>(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
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)
return mImpl->CreateBackgroundActor();
}
+void Controller::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ mImpl->GetAnchorActors(anchorActors);
+}
+
+int Controller::GetAnchorIndex(size_t characterOffset)
+{
+ return mImpl->GetAnchorIndex(characterOffset);
+}
+
Controller::Controller(ControlInterface* controlInterface,
EditableControlInterface* editableControlInterface,
SelectableControlInterface* selectableControlInterface,
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
#include <dali-toolkit/internal/text/hidden-text.h>
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.
*/
*/
CharacterIndex GetCursorPosition();
+ /**
+ * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
+ *
+ * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
+ */
+ void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
+
+ /**
+ * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
+ *
+ * @param[in] characterOffset A position in text coords.
+ *
+ * @return the index in anchor vector (-1 if an anchor not found)
+ */
+ int GetAnchorIndex(size_t characterOffset);
+
protected: // Inherit from Text::Decorator::ControllerInterface.
/**
* @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
*/
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.
}
break;
}
- case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
- {
- if(Dali::Accessibility::IsUp())
- {
- Dali::Accessibility::Accessible::Get(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::ROLE);
- }
- break;
- }
}
}