From: Richard Huang Date: Fri, 16 Oct 2020 10:34:02 +0000 (+0100) Subject: [dali_1.9.34] Merge branch 'devel/master' X-Git-Tag: dali_2.0.7~4^2~9 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=eac3e6ee30183868f1af12addd94e7f2fc467ed7;hp=8f568af864987ed3039737045db38ea3db4ac962 [dali_1.9.34] Merge branch 'devel/master' Change-Id: I18cc447c9a22f02583ac13f0b92edf10b88af081 --- diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 851ca00..4c31f29 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -28,6 +28,7 @@ SET(TC_SOURCES utc-Dali-Text-Typesetter.cpp utc-Dali-Text-ViewModel.cpp utc-Dali-TextField-internal.cpp + utc-Dali-TextEditor-internal.cpp utc-Dali-TextSelectionPopup-internal.cpp utc-Dali-TextureManager.cpp utc-Dali-Visuals-internal.cpp diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp new file mode 100755 index 0000000..9445be6 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 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. + * + */ + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace Dali; +using namespace Toolkit; +using namespace Text; + +int UtcDaliTextEditorSelectText(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliTextEditorSelectText" ); + + // Create a text editor + TextEditor textEditor = TextEditor::New(); + textEditor.SetProperty( Actor::Property::SIZE, Vector2( 400.f, 60.f ) ); + textEditor.SetProperty( TextEditor::Property::TEXT, "Hello World" ); + + // Add the text editor to the stage + application.GetScene().Add( textEditor ); + + application.SendNotification(); + application.Render(); + + Toolkit::Internal::TextEditor& textEditorImpl = GetImpl( textEditor ); + + application.SendNotification(); + application.Render(); + + // Highlight the whole text + textEditorImpl.SelectWholeText(); + + application.SendNotification(); + application.Render(); + + std::string selectedText = textEditorImpl.GetSelectedText(); + DALI_TEST_CHECK( selectedText == "Hello World" ); + + // Select None + textEditorImpl.SelectNone(); + + application.SendNotification(); + application.Render(); + + selectedText = textEditorImpl.GetSelectedText(); + DALI_TEST_CHECK( selectedText == "" ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp index a098f73..37d54e1 100755 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp @@ -112,3 +112,43 @@ int UtcDaliTextFieldMultipleBackgroundText(void) END_TEST; } + +int UtcDaliTextFieldSelectText(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliTextFieldSelectText" ); + + // Create a text field + TextField textField = TextField::New(); + textField.SetProperty( Actor::Property::SIZE, Vector2( 400.f, 60.f ) ); + textField.SetProperty( TextField::Property::TEXT, "Hello World" ); + + // Add the text field to the stage + application.GetScene().Add( textField ); + + application.SendNotification(); + application.Render(); + + Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField ); + + application.SendNotification(); + application.Render(); + + // Highlight the whole text + textFieldImpl.SelectWholeText(); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( textFieldImpl.GetSelectedText() == "Hello World" ); + + // Select None + textFieldImpl.SelectNone(); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( textFieldImpl.GetSelectedText() == "" ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp index 574cbf9..7a3ce4c 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -2861,6 +2861,107 @@ int utcDaliTextEditorMaxCharactersReached(void) END_TEST; } +int UtcDaliTextEditorSelectWholeText(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextEditorSelectWholeText "); + + TextEditor textEditor = TextEditor::New(); + + application.GetScene().Add( textEditor ); + + textEditor.SetProperty( Actor::Property::SIZE, Vector2( 300.f, 50.f ) ); + textEditor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT ); + textEditor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT ); + + // Avoid a crash when core load gl resources. + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1u, textEditor.GetChildCount(), TEST_LOCATION ); + + DevelTextEditor::SelectWholeText( textEditor ); + + application.SendNotification(); + application.Render(); + + // Nothing should have been selected. The number of children is still 1 + DALI_TEST_EQUALS( 1u, textEditor.GetChildCount(), TEST_LOCATION ); + + textEditor.SetProperty( TextEditor::Property::TEXT, "Hello world" ); + + application.SendNotification(); + application.Render(); + + DevelTextEditor::SelectWholeText( textEditor ); + + application.SendNotification(); + application.Render(); + + // Should be 2 children, the stencil and the layer + DALI_TEST_EQUALS( 2u, textEditor.GetChildCount(), TEST_LOCATION ); + + // The offscreen root actor should have two actors: the renderer and the highlight actor. + Actor stencil = textEditor.GetChildAt( 0u ); + + // The highlight actor is drawn first, so is the first actor in the list + Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u ); + DALI_TEST_CHECK( highlight ); + + END_TEST; +} + +int UtcDaliTextEditorSelectNone(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextEditorSelectWholeText "); + + TextEditor textEditor = TextEditor::New(); + + application.GetScene().Add( textEditor ); + + textEditor.SetProperty( Actor::Property::SIZE, Vector2( 300.f, 50.f ) ); + textEditor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT ); + textEditor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT ); + + // Avoid a crash when core load gl resources. + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + application.SendNotification(); + application.Render(); + + textEditor.SetProperty( TextEditor::Property::TEXT, "Hello world" ); + + application.SendNotification(); + application.Render(); + + // Nothing is selected + std::string selectedText = textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get(); + DALI_TEST_EQUALS( "", selectedText, TEST_LOCATION ); + + DevelTextEditor::SelectWholeText( textEditor ); + + application.SendNotification(); + application.Render(); + + // whole text is selected + selectedText = textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get(); + DALI_TEST_EQUALS( "Hello world", selectedText, TEST_LOCATION ); + + DevelTextEditor::SelectNone( textEditor ); + + application.SendNotification(); + application.Render(); + + // Nothing is selected + selectedText = textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get(); + DALI_TEST_EQUALS( "", selectedText, TEST_LOCATION ); + + END_TEST; +} + int UtcDaliTextEditorSelectRange(void) { ToolkitTestApplication application; @@ -2882,6 +2983,10 @@ int UtcDaliTextEditorSelectRange(void) textEditor.SetProperty( DevelTextEditor::Property::SELECTED_TEXT_START, 0 ); textEditor.SetProperty( DevelTextEditor::Property::SELECTED_TEXT_END, 5 ); + // Hello is selected + std::string selectedText = textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get(); + DALI_TEST_EQUALS( "Hello", selectedText, TEST_LOCATION ); + DALI_TEST_EQUALS( textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT_START ).Get(), 0, TEST_LOCATION ); DALI_TEST_EQUALS( textEditor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT_END ).Get(), 5, TEST_LOCATION ); diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp index 5858d99..adcff4c 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp +++ b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp @@ -35,6 +35,16 @@ MaxLengthReachedSignalType& MaxLengthReachedSignal(TextEditor textEditor) return GetImpl(textEditor).MaxLengthReachedSignal(); } +void SelectWholeText(TextEditor textEditor) +{ + GetImpl(textEditor).SelectWholeText(); +} + +void SelectNone(TextEditor textEditor) +{ + GetImpl(textEditor).SelectNone(); +} + } // namespace DevelTextEditor } // namespace Toolkit diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h index 619f91a..0db66e5 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h @@ -84,41 +84,41 @@ enum Type LINE_WRAP_MODE = Dali::Toolkit::TextEditor::Property::LINE_WRAP_MODE, /** - * @brief The text to display when the TextEditor is empty and inactive. - * @details Name "placeholderText", type Property::STRING. - */ + * @brief The text to display when the TextEditor is empty and inactive. + * @details Name "placeholderText", type Property::STRING. + */ PLACEHOLDER_TEXT, /** - * @brief The placeholder-text color. - * @details Name "placeholderTextColor", type Property::VECTOR4. - */ + * @brief The placeholder-text color. + * @details Name "placeholderTextColor", type Property::VECTOR4. + */ PLACEHOLDER_TEXT_COLOR, /** - * @brief Enables Text selection using Shift key. - * @details Name "enableShiftSelection", type Property::BOOLEAN. - */ + * @brief Enables Text selection using Shift key. + * @details Name "enableShiftSelection", type Property::BOOLEAN. + */ ENABLE_SHIFT_SELECTION, /** - * @brief Enables the grab handles for text selection. - * @details Name "enableGrabHandle", type Property::BOOLEAN. - * @note The default value is true, which means the grab handles are enabled by default. - */ + * @brief Enables the grab handles for text selection. + * @details Name "enableGrabHandle", type Property::BOOLEAN. + * @note The default value is true, which means the grab handles are enabled by default. + */ ENABLE_GRAB_HANDLE, /** - * @brief Modifies the default text alignment to match the direction of the system language. - * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write - * @note The default value is false - */ + * @brief Modifies the default text alignment to match the direction of the system language. + * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write + * @note The default value is false + */ MATCH_SYSTEM_LANGUAGE_DIRECTION, /** - * @brief The type or rendering e.g. bitmap-based. - * @details Name "renderingBackend", type Property::INTEGER. - */ + * @brief The type or rendering e.g. bitmap-based. + * @details Name "renderingBackend", type Property::INTEGER. + */ RENDERING_BACKEND, /** @@ -141,9 +141,16 @@ enum Type /** * @brief The Editable state of control. - * @details Name "editable", type Property::BOOL. + * @details Name "enableEditing", type Property::BOOLEAN. */ ENABLE_EDITING, + + /** + * @brief The selected text in UTF-8 format. + * @details Name "selectedText", type Property::STRING. + * @note This property is read-only. + */ + SELECTED_TEXT, }; } // namespace Property @@ -173,6 +180,20 @@ using MaxLengthReachedSignalType = Signal; */ DALI_TOOLKIT_API MaxLengthReachedSignalType& MaxLengthReachedSignal(TextEditor textEditor); +/** + * @brief Select the whole text of TextEditor. + * + * @param[in] textEditor The instance of TextEditor. + */ +DALI_TOOLKIT_API void SelectWholeText(TextEditor textEditor); + +/** + * @brief Unselect the whole text of TextEditor. + * + * @param[in] textEditor The instance of TextEditor. + */ +DALI_TOOLKIT_API void SelectNone(TextEditor textEditor); + } // namespace DevelTextEditor } // namespace Toolkit diff --git a/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h index 824d83c..cec1709 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h @@ -84,51 +84,51 @@ enum ELLIPSIS = Dali::Toolkit::TextField::Property::ELLIPSIS, /** - * @brief Enables Text selection using Shift key. - * @details Name "enableShiftSelection", type Property::BOOLEAN. - */ + * @brief Enables Text selection using Shift key. + * @details Name "enableShiftSelection", type Property::BOOLEAN. + */ ENABLE_SHIFT_SELECTION = ELLIPSIS + 1, /** - * @brief Enables the grab handles for text selection. - * @details Name "enableGrabHandle", type Property::BOOLEAN. - * @note The default value is true, which means the grab handles are enabled by default. - */ + * @brief Enables the grab handles for text selection. + * @details Name "enableGrabHandle", type Property::BOOLEAN. + * @note The default value is true, which means the grab handles are enabled by default. + */ ENABLE_GRAB_HANDLE = ELLIPSIS + 2, /** - * @brief Modifies the default text alignment to match the direction of the system language. - * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write - * @note The default value is false - */ + * @brief Modifies the default text alignment to match the direction of the system language. + * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write + * @note The default value is false + */ MATCH_SYSTEM_LANGUAGE_DIRECTION = ELLIPSIS + 3, /** - * @brief Enables the grab handle popup for text selection. - * @details Name "enableGrabHandlePopup", type Property::BOOLEAN. - * @note The default value is true, which means the grab handle popup is enabled by default. - */ + * @brief Enables the grab handle popup for text selection. + * @details Name "enableGrabHandlePopup", type Property::BOOLEAN. + * @note The default value is true, which means the grab handle popup is enabled by default. + */ ENABLE_GRAB_HANDLE_POPUP = ELLIPSIS + 4, /** - * @brief The default text background parameters. - * @details Name "textBackground", type Property::VECTOR4. - * @note Use "textBackground" as property name to avoid conflict with Control's "background" property. - * @note The default value is Color::TRANSPARENT. - */ + * @brief The default text background parameters. + * @details Name "textBackground", type Property::VECTOR4. + * @note Use "textBackground" as property name to avoid conflict with Control's "background" property. + * @note The default value is Color::TRANSPARENT. + */ BACKGROUND = ELLIPSIS + 5, /** - * @brief The selected text in UTF-8 format. - * @details Name "selectedText", type Property::STRING. - * @note This property is read-only. - */ + * @brief The selected text in UTF-8 format. + * @details Name "selectedText", type Property::STRING. + * @note This property is read-only. + */ SELECTED_TEXT = ELLIPSIS + 6, /** - * @brief The type or rendering e.g. bitmap-based. - * @details Name "renderingBackend", type Property::INTEGER. - */ + * @brief The type or rendering e.g. bitmap-based. + * @details Name "renderingBackend", type Property::INTEGER. + */ RENDERING_BACKEND = ELLIPSIS + 7, /** @@ -145,7 +145,7 @@ enum /** * @brief The Editable state of control. - * @details Name "editable", type Property::BOOL. + * @details Name "enableEditing", type Property::BOOLEAN. */ ENABLE_EDITING, diff --git a/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h index cf36405..d325a9c 100644 --- a/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h +++ b/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h @@ -62,10 +62,6 @@ enum } // namespace DevelColorVisual -/** - * @} - */ - } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp index 4224df2..60db674 100644 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp @@ -143,6 +143,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "maxLength", DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectedTextStart", INTEGER, SELECTED_TEXT_START ) DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectedTextEnd", INTEGER, SELECTED_TEXT_END ) DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableEditing", BOOLEAN, ENABLE_EDITING ) +DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextEditor, "selectedText", STRING, SELECTED_TEXT ) DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED ) DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED ) @@ -701,22 +702,16 @@ void TextEditor::SetProperty( BaseObject* object, Property::Index index, const P } case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START: { - if( impl.mController ) - { - uint32_t start = static_cast(value.Get< int >()); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start ); - impl.SetTextSelectionRange( &start, nullptr ); - } + uint32_t start = static_cast(value.Get< int >()); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start ); + impl.SetTextSelectionRange( &start, nullptr ); break; } case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END: { - if( impl.mController ) - { - uint32_t end = static_cast(value.Get< int >()); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end ); - impl.SetTextSelectionRange( nullptr, &end ); - } + uint32_t end = static_cast(value.Get< int >()); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end ); + impl.SetTextSelectionRange( nullptr, &end ); break; } case Toolkit::DevelTextEditor::Property::ENABLE_EDITING: @@ -1040,6 +1035,11 @@ Property::Value TextEditor::GetProperty( BaseObject* object, Property::Index ind value = impl.mController->GetMaximumNumberOfCharacters(); break; } + case Toolkit::DevelTextEditor::Property::SELECTED_TEXT: + { + value = impl.mController->GetSelectedText( ); + break; + } case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START: { Uint32Pair range = impl.GetTextSelectionRange(); @@ -1063,6 +1063,33 @@ Property::Value TextEditor::GetProperty( BaseObject* object, Property::Index ind return value; } +void TextEditor::SelectWholeText() +{ + if( mController && mController->IsShowingRealText() ) + { + mController->SelectWholeText(); + SetKeyInputFocus(); + } +} + +void TextEditor::SelectNone() +{ + if( mController && mController->IsShowingRealText() ) + { + mController->SelectNone(); + } +} + +string TextEditor::GetSelectedText() const +{ + string selectedText = ""; + if( mController && mController->IsShowingRealText() ) + { + selectedText = mController->GetSelectedText( ); + } + return selectedText; +} + InputMethodContext TextEditor::GetInputMethodContext() { return mInputMethodContext; diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h index f89520e..2aca941 100755 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h @@ -216,6 +216,21 @@ public: Uint32Pair GetTextSelectionRange() const override; /** + * @copydoc Text::SelectableControlInterface::SelectWholeText() + */ + void SelectWholeText() override; + + /** + * @copydoc Text::SelectableControlInterface::SelectNone() + */ + void SelectNone() override; + + /** + * @copydoc Text::SelectableControlInterface::GetSelectedText() + */ + string GetSelectedText() const override; + + /** * @copydoc Text::EditableControlInterface::IsEditable() */ bool IsEditable() const override; diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index c038d08..a85a342 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -714,22 +714,16 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr } case Toolkit::DevelTextField::Property::SELECTED_TEXT_START: { - if( impl.mController ) - { - uint32_t start = static_cast(value.Get< int >()); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start ); - impl.SetTextSelectionRange( &start, nullptr ); - } + uint32_t start = static_cast(value.Get< int >()); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start ); + impl.SetTextSelectionRange( &start, nullptr ); break; } case Toolkit::DevelTextField::Property::SELECTED_TEXT_END: { - if( impl.mController ) - { - uint32_t end = static_cast(value.Get< int >()); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end ); - impl.SetTextSelectionRange( nullptr, &end ); - } + uint32_t end = static_cast(value.Get< int >()); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end ); + impl.SetTextSelectionRange( nullptr, &end ); break; } case Toolkit::DevelTextField::Property::ENABLE_EDITING: @@ -1089,7 +1083,7 @@ void TextField::SelectWholeText() { if( mController && mController->IsShowingRealText() ) { - mController->SelectEvent( 0.f, 0.f, SelectionType::ALL ); + mController->SelectWholeText(); SetKeyInputFocus(); } } @@ -1098,9 +1092,18 @@ void TextField::SelectNone() { if( mController && mController->IsShowingRealText() ) { - mController->SelectEvent( 0.f, 0.f, SelectionType::NONE ); - SetKeyInputFocus(); + mController->SelectNone(); + } +} + +string TextField::GetSelectedText() const +{ + string selectedText = ""; + if( mController && mController->IsShowingRealText() ) + { + selectedText = mController->GetSelectedText( ); } + return selectedText; } void TextField::SetTextSelectionRange(const uint32_t *start, const uint32_t *end) diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.h b/dali-toolkit/internal/controls/text-controls/text-field-impl.h index 165234b..329d7b5 100755 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.h @@ -103,16 +103,6 @@ public: */ Toolkit::TextField::InputStyleChangedSignalType& InputStyleChangedSignal(); - /** - * @brief Called to select the whole texts. - */ - void SelectWholeText(); - - /** - * @brief Called to unselect the whole texts. - */ - void SelectNone(); - private: // From Control /** @@ -217,6 +207,21 @@ public: Uint32Pair GetTextSelectionRange() const override; /** + * @copydoc Text::SelectableControlInterface::SelectWholeText() + */ + void SelectWholeText() override; + + /** + * @copydoc Text::SelectableControlInterface::SelectNone() + */ + void SelectNone() override; + + /** + * @copydoc Text::SelectableControlInterface::GetSelectedText() + */ + string GetSelectedText() const override; + + /** * @copydoc Text::EditableControlInterface::IsEditable() */ bool IsEditable() const override; diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index f35ae3f..0d6b781 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -140,7 +140,10 @@ SET( toolkit_src_files ${toolkit_src_dir}/text/shaper.cpp ${toolkit_src_dir}/text/text-enumerations-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-input-font-handler.cpp + ${toolkit_src_dir}/text/text-controller-placeholder-handler.cpp ${toolkit_src_dir}/text/text-effects-style.cpp ${toolkit_src_dir}/text/text-font-style.cpp ${toolkit_src_dir}/text/text-io.cpp diff --git a/dali-toolkit/internal/text/text-controller-event-handler.cpp b/dali-toolkit/internal/text/text-controller-event-handler.cpp new file mode 100644 index 0000000..b9b260b --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-event-handler.cpp @@ -0,0 +1,908 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace +{ + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#endif + +const std::string KEY_C_NAME = "c"; +const std::string KEY_V_NAME = "v"; +const std::string KEY_X_NAME = "x"; +const std::string KEY_A_NAME = "a"; +const std::string KEY_INSERT_NAME = "Insert"; + +} // namespace + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void Controller::EventHandler::KeyboardFocusGainEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( ( EventData::INACTIVE == controller.mImpl->mEventData->mState ) || + ( EventData::INTERRUPTED == controller.mImpl->mEventData->mState ) ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + controller.mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered. + controller.mImpl->mEventData->mUpdateInputStyle = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + controller.mImpl->NotifyInputMethodContextMultiLineStatus(); + if( controller.mImpl->IsShowingPlaceholderText() ) + { + // Show alternative placeholder-text when editing + controller.ShowPlaceholderText(); + } + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::KeyboardFocusLostEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( EventData::INTERRUPTED != controller.mImpl->mEventData->mState ) + { + controller.mImpl->ChangeState( EventData::INACTIVE ); + + if( !controller.mImpl->IsShowingRealText() ) + { + // Revert to regular placeholder-text when not editing + controller.ShowPlaceholderText(); + } + } + } + controller.mImpl->RequestRelayout(); +} + +bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyEvent" ); + + bool textChanged = false; + bool relayoutNeeded = false; + + if( ( NULL != controller.mImpl->mEventData ) && + ( keyEvent.GetState() == KeyEvent::DOWN ) ) + { + int keyCode = keyEvent.GetKeyCode(); + const std::string& keyString = keyEvent.GetKeyString(); + const std::string keyName = keyEvent.GetKeyName(); + + const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); + + // Pre-process to separate modifying events from non-modifying input events. + if( isNullKey ) + { + // In some platforms arrive key events with no key code. + // Do nothing. + return false; + } + else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) + { + // Do nothing + return false; + } + else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || + ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) ) + { + // If don't have any text, do nothing. + if( !controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) + { + return false; + } + + uint32_t cursorPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + uint32_t numberOfCharacters = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + uint32_t cursorLine = controller.mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition ); + uint32_t numberOfLines = controller.mImpl->mModel->GetNumberOfLines(); + + // Logic to determine whether this text control will lose focus or not. + if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) || + ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) ) + { + // Release the active highlight. + if( controller.mImpl->mEventData->mState == EventData::SELECTING ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + + // Update selection position. + controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->RequestRelayout(); + } + return false; + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + Event event( Event::CURSOR_KEY_EVENT ); + event.p1.mInt = keyCode; + event.p2.mBool = keyEvent.IsShiftModifier(); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + // Will request for relayout. + relayoutNeeded = true; + } + else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) + { + // Left or Right Control key event is received before Ctrl-C/V/X key event is received + // If not handle it here, any selected text will be deleted + + // Do nothing + return false; + } + else if ( keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier()) + { + bool consumed = false; + if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME) + { + // Ctrl-C or Ctrl+Insert to copy the selected text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY ); + consumed = true; + } + else if (keyName == KEY_V_NAME) + { + // Ctrl-V to paste the copied text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE ); + consumed = true; + } + else if (keyName == KEY_X_NAME) + { + // Ctrl-X to cut the selected text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT ); + consumed = true; + } + else if (keyName == KEY_A_NAME) + { + // Ctrl-A to select All the text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL ); + consumed = true; + } + return consumed; + } + else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) || + ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) ) + { + textChanged = controller.DeleteEvent( keyCode ); + + // Will request for relayout. + relayoutNeeded = true; + } + else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) || + IsKey( keyEvent, Dali::DALI_KEY_MENU ) || + IsKey( keyEvent, Dali::DALI_KEY_HOME ) ) + { + // Power key/Menu/Home key behaviour does not allow edit mode to resume. + controller.mImpl->ChangeState( EventData::INACTIVE ); + + // Will request for relayout. + relayoutNeeded = true; + + // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. + } + else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) ) + { + // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled + // and a character is typed after the type of a upper case latin character. + + // Do nothing. + return false; + } + else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) ) + { + // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. + // Do nothing. + return false; + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str() ); + if (!controller.IsEditable()) return false; + + if( !keyString.empty() ) + { + // InputMethodContext is no longer handling key-events + controller.mImpl->ClearPreEditFlag(); + + controller.InsertText( keyString, COMMIT ); + + textChanged = true; + + // Will request for relayout. + relayoutNeeded = true; + } + + } + + if ( ( controller.mImpl->mEventData->mState != EventData::INTERRUPTED ) && + ( controller.mImpl->mEventData->mState != EventData::INACTIVE ) && + ( !isNullKey ) && + ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) && + ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) && + ( Dali::DALI_KEY_VOLUME_UP != keyCode ) && + ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) ) + { + // Should not change the state if the key is the shift send by the InputMethodContext. + // Otherwise, when the state is SELECTING the text controller can't send the right + // surrounding info to the InputMethodContext. + controller.mImpl->ChangeState( EventData::EDITING ); + + // Will request for relayout. + relayoutNeeded = true; + } + + if( relayoutNeeded ) + { + controller.mImpl->RequestRelayout(); + } + } + + if( textChanged && + ( NULL != controller.mImpl->mEditableControlInterface ) ) + { + // Do this last since it provides callbacks into application code + controller.mImpl->mEditableControlInterface->TextChanged(); + } + + return true; +} + +void Controller::EventHandler::TapEvent(Controller& controller, unsigned int tapCount, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected TapEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", controller.mImpl->mEventData->mState ); + EventData::State state( controller.mImpl->mEventData->mState ); + bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field + + if( controller.mImpl->IsClipboardVisible() ) + { + if( EventData::INACTIVE == state || EventData::EDITING == state) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + } + relayoutNeeded = true; + } + else if( 1u == tapCount ) + { + if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required. + } + + if( controller.mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + relayoutNeeded = true; + } + else + { + if( controller.mImpl->IsShowingPlaceholderText() && !controller.mImpl->IsFocusedPlaceholderAvailable() ) + { + // Hide placeholder text + controller.ResetText(); + } + + if( EventData::INACTIVE == state ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + } + else if( !controller.mImpl->IsClipboardEmpty() ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); + } + relayoutNeeded = true; + } + } + else if( 2u == tapCount ) + { + if( controller.mImpl->mEventData->mSelectionEnabled && + controller.mImpl->IsShowingRealText() ) + { + relayoutNeeded = true; + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + } + } + + // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated + if( relayoutNeeded ) + { + Event event( Event::TAP_EVENT ); + event.p1.mUint = tapCount; + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } + } + + // Reset keyboard as tap event has occurred. + controller.mImpl->ResetInputMethodContext(); +} + +void Controller::EventHandler::PanEvent(Controller& controller, GestureState state, const Vector2& displacement) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected PanEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + Event event( Event::PAN_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = displacement.x; + event.p3.mFloat = displacement.y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::LongPressEvent(Controller& controller, GestureState state, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected LongPressEvent" ); + + if( ( state == GestureState::STARTED ) && + ( NULL != controller.mImpl->mEventData ) ) + { + // The 1st long-press on inactive text-field is treated as tap + if( EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + + Event event( Event::TAP_EVENT ); + event.p1.mUint = 1; + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } + else if( !controller.mImpl->IsShowingRealText() ) + { + Event event( Event::LONG_PRESS_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + controller.mImpl->RequestRelayout(); + } + else if( !controller.mImpl->IsClipboardVisible() ) + { + // Reset the InputMethodContext to commit the pre-edit before selecting the text. + controller.mImpl->ResetInputMethodContext(); + + Event event( Event::LONG_PRESS_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + controller.mImpl->RequestRelayout(); + + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + } + } +} + +void Controller::EventHandler::SelectEvent(Controller& controller, float x, float y, SelectionType selectType) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( selectType == SelectionType::ALL ) + { + Event event( Event::SELECT_ALL ); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + else if( selectType == SelectionType::NONE ) + { + Event event( Event::SELECT_NONE ); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + else + { + Event event( Event::SELECT ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::ProcessModifyEvents(Controller& controller) +{ + Vector& events = controller.mImpl->mModifyEvents; + + if( 0u == events.Count() ) + { + // Nothing to do. + return; + } + + for( Vector::ConstIterator it = events.Begin(), + endIt = events.End(); + it != endIt; + ++it ) + { + const ModifyEvent& event = *it; + + if( ModifyEvent::TEXT_REPLACED == event.type ) + { + // A (single) replace event should come first, otherwise we wasted time processing NOOP events + DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" ); + + controller.TextReplacedEvent(); + } + else if( ModifyEvent::TEXT_INSERTED == event.type ) + { + controller.TextInsertedEvent(); + } + else if( ModifyEvent::TEXT_DELETED == event.type ) + { + // Placeholder-text cannot be deleted + if( !controller.mImpl->IsShowingPlaceholderText() ) + { + controller.TextDeletedEvent(); + } + } + } + + if( NULL != controller.mImpl->mEventData ) + { + // When the text is being modified, delay cursor blinking + controller.mImpl->mEventData->mDecorator->DelayCursorBlink(); + + // Update selection position after modifying the text + controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + } + + // DISCARD temporary text + events.Clear(); +} + +void Controller::EventHandler::TextReplacedEvent(Controller& controller) +{ + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +void Controller::EventHandler::TextInsertedEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( NULL != controller.mImpl->mEventData && "Unexpected TextInsertedEvent" ); + + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model; TODO - Optimize this + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +void Controller::EventHandler::TextDeletedEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( NULL != controller.mImpl->mEventData && "Unexpected TextDeletedEvent" ); + + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + if (!controller.IsEditable()) return; + + controller.mImpl->mEventData->mCheckScrollAmount = true; + + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model; TODO - Optimize this + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", &controller, keyCode ); + + bool removed = false; + + if( NULL == controller.mImpl->mEventData ) + { + return removed; + } + + if (!controller.IsEditable()) return false; + + // InputMethodContext is no longer handling key-events + controller.mImpl->ClearPreEditFlag(); + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + removed = controller.RemoveSelectedText(); + } + else if( ( controller.mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) ) + { + // Remove the character before the current cursor position + removed = controller.RemoveText( -1, + 1, + UPDATE_INPUT_STYLE ); + } + else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) + { + // Remove the character after the current cursor position + removed = controller.RemoveText( 0, + 1, + UPDATE_INPUT_STYLE ); + } + + if( removed ) + { + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + } + + return removed; +} + +InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent) +{ + // Whether the text needs to be relaid-out. + bool requestRelayout = false; + + // Whether to retrieve the text and cursor position to be sent to the InputMethodContext. + bool retrieveText = false; + bool retrieveCursor = false; + + switch( inputMethodContextEvent.eventName ) + { + case InputMethodContext::COMMIT: + { + controller.InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT ); + requestRelayout = true; + retrieveCursor = true; + break; + } + case InputMethodContext::PRE_EDIT: + { + controller.InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT ); + requestRelayout = true; + retrieveCursor = true; + break; + } + case InputMethodContext::DELETE_SURROUNDING: + { + const bool textDeleted = controller.RemoveText( inputMethodContextEvent.cursorOffset, + inputMethodContextEvent.numberOfChars, + DONT_UPDATE_INPUT_STYLE ); + + if( textDeleted ) + { + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + + requestRelayout = true; + } + break; + } + case InputMethodContext::GET_SURROUNDING: + { + retrieveText = true; + retrieveCursor = true; + break; + } + case InputMethodContext::PRIVATE_COMMAND: + { + // PRIVATECOMMAND event is just for getting the private command message + retrieveText = true; + retrieveCursor = true; + break; + } + case InputMethodContext::VOID: + { + // do nothing + break; + } + } // end switch + + if( requestRelayout ) + { + controller.mImpl->mOperationsPending = ALL_OPERATIONS; + controller.mImpl->RequestRelayout(); + } + + std::string text; + CharacterIndex cursorPosition = 0u; + Length numberOfWhiteSpaces = 0u; + + if( retrieveCursor ) + { + numberOfWhiteSpaces = controller.mImpl->GetNumberOfWhiteSpaces( 0u ); + + cursorPosition = controller.mImpl->GetLogicalCursorPosition(); + + if( cursorPosition < numberOfWhiteSpaces ) + { + cursorPosition = 0u; + } + else + { + cursorPosition -= numberOfWhiteSpaces; + } + } + + if( retrieveText ) + { + if( !controller.mImpl->IsShowingPlaceholderText() ) + { + // Retrieves the normal text string. + controller.mImpl->GetText( numberOfWhiteSpaces, text ); + } + else + { + // When the current text is Placeholder Text, the surrounding text should be empty string. + // It means DALi should send empty string ("") to IME. + text = ""; + } + } + + InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); + + if( requestRelayout && + ( NULL != controller.mImpl->mEditableControlInterface ) ) + { + // Do this last since it provides callbacks into application code + controller.mImpl->mEditableControlInterface->TextChanged(); + } + + return callbackData; +} + +void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller) +{ + // Retrieve the clipboard contents first + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + std::string stringToPaste( notifier.GetContent() ); + + // Commit the current pre-edit text; the contents of the clipboard should be appended + controller.mImpl->ResetInputMethodContext(); + + // Temporary disable hiding clipboard + controller.mImpl->SetClipboardHideEnable( false ); + + // Paste + controller.PasteText( stringToPaste ); + + controller.mImpl->SetClipboardHideEnable( true ); +} + +void Controller::EventHandler::DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected DecorationEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + switch( handleType ) + { + case GRAB_HANDLE: + { + Event event( Event::GRAB_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case LEFT_SELECTION_HANDLE: + { + Event event( Event::LEFT_SELECTION_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case RIGHT_SELECTION_HANDLE: + { + Event event( Event::RIGHT_SELECTION_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case LEFT_SELECTION_HANDLE_MARKER: + case RIGHT_SELECTION_HANDLE_MARKER: + { + // Markers do not move the handles. + break; + } + case HANDLE_TYPE_COUNT: + { + DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); + } + } + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button) +{ + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + switch( button ) + { + case Toolkit::TextSelectionPopup::CUT: + { + if (!controller.IsEditable()) return; + controller.mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text + controller.mImpl->mOperationsPending = ALL_OPERATIONS; + + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + + controller.mImpl->RequestRelayout(); + + if( NULL != controller.mImpl->mEditableControlInterface ) + { + controller.mImpl->mEditableControlInterface->TextChanged(); + } + break; + } + case Toolkit::TextSelectionPopup::COPY: + { + controller.mImpl->SendSelectionToClipboard( false ); // Text not modified + + controller.mImpl->mEventData->mUpdateCursorPosition = true; + + controller.mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup + break; + } + case Toolkit::TextSelectionPopup::PASTE: + { + controller.mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item + break; + } + case Toolkit::TextSelectionPopup::SELECT: + { + const Vector2& currentCursorPosition = controller.mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); + + if( controller.mImpl->mEventData->mSelectionEnabled ) + { + // Creates a SELECT event. + controller.SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE ); + } + break; + } + case Toolkit::TextSelectionPopup::SELECT_ALL: + { + // Creates a SELECT_ALL event + controller.SelectEvent( 0.f, 0.f, SelectionType::ALL ); + break; + } + case Toolkit::TextSelectionPopup::CLIPBOARD: + { + controller.mImpl->ShowClipboard(); + break; + } + case Toolkit::TextSelectionPopup::NONE: + { + // Nothing to do. + break; + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-event-handler.h b/dali-toolkit/internal/text/text-controller-event-handler.h new file mode 100644 index 0000000..51d1648 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-event-handler.h @@ -0,0 +1,67 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H + +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::EventHandler +{ + static void KeyboardFocusGainEvent(Controller& controller); + static void KeyboardFocusLostEvent(Controller& controller); + static bool KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent); + static void TapEvent(Controller& controller, unsigned int tapCount, float x, float y); + static void PanEvent(Controller& controller, GestureState state, const Vector2& displacement); + static void LongPressEvent(Controller& controller, GestureState state, float x, float y); + static void SelectEvent(Controller& controller, float x, float y, SelectionType selectType); + static void ProcessModifyEvents(Controller& controller); + static void TextReplacedEvent(Controller& controller); + static void TextInsertedEvent(Controller& controller); + static void TextDeletedEvent(Controller& controller); + static bool DeleteEvent(Controller& controller, int keyCode); + static InputMethodContext::CallbackData OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent); + static void PasteClipboardItemEvent(Controller& controller); + static void DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y); + static void TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller-input-font-handler.cpp b/dali-toolkit/internal/text/text-controller-input-font-handler.cpp new file mode 100644 index 0000000..21bd604 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-input-font-handler.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +namespace +{ + +/** + * @brief Adds a new font description run for the selected text. + * + * The new font parameters are added after the call to this method. + * + * @param[in] eventData The event data pointer. + * @param[in] logicalModel The logical model where to add the new font description run. + * @param[out] startOfSelectedText Index to the first selected character. + * @param[out] lengthOfSelectedText Number of selected characters. + */ +FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData, + LogicalModelPtr logicalModel, + CharacterIndex& startOfSelectedText, + Length& lengthOfSelectedText ) +{ + const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition; + + // Get start and end position of selection + startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition; + lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText; + + // Add the font run. + const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); + logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); + + FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); + + fontDescriptionRun.characterRun.characterIndex = startOfSelectedText; + fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText; + + // Recalculate the selection highlight as the metrics may have changed. + eventData->mUpdateLeftSelectionPosition = true; + eventData->mUpdateRightSelectionPosition = true; + eventData->mUpdateHighlightBox = true; + + return fontDescriptionRun; +} + +} // unnamed namespace + +void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.familyName = fontFamily; + controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.familyLength = fontFamily.size(); + fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; + memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); + fontDescriptionRun.familyDefined = true; + + // The memory allocated for the font family name is freed when the font description is removed from the logical model. + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font changes, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.familyName; + } + + // Return the default font's family if there is no EventData. + return controller.GetDefaultFontFamily(); +} + +void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.weight = weight; + controller.mImpl->mEventData->mInputStyle.isWeightDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.weight = weight; + fontDescriptionRun.weightDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined; + } + + return defined; +} + +FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.weight; + } + + return controller.GetDefaultFontWeight(); +} + +void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.width = width; + controller.mImpl->mEventData->mInputStyle.isWidthDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.width = width; + fontDescriptionRun.widthDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined; + } + + return defined; +} + +FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.width; + } + + return controller.GetDefaultFontWidth(); +} + +void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.slant = slant; + controller.mImpl->mEventData->mInputStyle.isSlantDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.slant = slant; + fontDescriptionRun.slantDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined; + } + + return defined; +} + +FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.slant; + } + + return controller.GetDefaultFontSlant(); +} + +void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.size = size; + controller.mImpl->mEventData->mInputStyle.isSizeDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.size = static_cast( size * 64.f ); + fontDescriptionRun.sizeDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.size; + } + + // Return the default font's point size if there is no EventData. + return controller.GetDefaultFontSize( Text::Controller::POINT_SIZE ); +} +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-input-font-handler.h b/dali-toolkit/internal/text/text-controller-input-font-handler.h new file mode 100644 index 0000000..066ac49 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-input-font-handler.h @@ -0,0 +1,60 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H + +/* + * Copyright (c) 2020 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 + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::InputFontHandler +{ + static void SetInputFontFamily(Controller& controller, const std::string& fontFamily); + static const std::string& GetInputFontFamily(const Controller& controller); + static void SetInputFontWeight(const Controller& controller, FontWeight weight); + static bool IsInputFontWeightDefined(const Controller& controller); + static FontWeight GetInputFontWeight(const Controller& controller); + static void SetInputFontWidth(Controller& controller, FontWidth width); + static bool IsInputFontWidthDefined(const Controller& controller); + static FontWidth GetInputFontWidth(const Controller& controller); + static void SetInputFontSlant(Controller& controller, FontSlant slant); + static bool IsInputFontSlantDefined(const Controller& controller); + static FontSlant GetInputFontSlant(const Controller& controller); + static void SetInputFontPointSize(Controller& controller, float size); + static float GetInputFontPointSize(const Controller& controller); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp b/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp new file mode 100644 index 0000000..f567cbd --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace +{ + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#endif + +const std::string EMPTY_STRING(""); + +const char * const PLACEHOLDER_TEXT = "text"; +const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused"; +const char * const PLACEHOLDER_COLOR = "color"; +const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily"; +const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; +const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; +const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; +const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; + +} // namespace + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled) +{ + controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled; + controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true; + + // Update placeholder if there is no text + if( controller.mImpl->IsShowingPlaceholderText() || + ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) ) + { + controller.ShowPlaceholderText(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller) +{ + return controller.mImpl->mEventData->mIsPlaceholderElideEnabled; +} + +void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( PLACEHOLDER_TYPE_INACTIVE == type ) + { + controller.mImpl->mEventData->mPlaceholderTextInactive = text; + } + else + { + controller.mImpl->mEventData->mPlaceholderTextActive = text; + } + + // Update placeholder if there is no text + if( controller.mImpl->IsShowingPlaceholderText() || + ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) ) + { + controller.ShowPlaceholderText(); + } + } +} + +void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( PLACEHOLDER_TYPE_INACTIVE == type ) + { + text = controller.mImpl->mEventData->mPlaceholderTextInactive; + } + else + { + text = controller.mImpl->mEventData->mPlaceholderTextActive; + } + } +} + +void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily; + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str()); + controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty(); + + controller.mImpl->RequestRelayout(); + } +} + +const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family; + } + + return EMPTY_STRING; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight; + controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->weightDefined; + } + return false; +} + +FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight; + } + + return TextAbstraction::FontWeight::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width; + controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->widthDefined; + } + return false; +} + +FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width; + } + + return TextAbstraction::FontWidth::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; + controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->slantDefined; + } + return false; +} + +FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; + } + + return TextAbstraction::FontSlant::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + switch( type ) + { + case POINT_SIZE: + { + controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize; + controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true; + controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag + break; + } + case PIXEL_SIZE: + { + // Point size = Pixel size * 72.f / DPI + unsigned int horizontalDpi = 0u; + unsigned int verticalDpi = 0u; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.GetDpi( horizontalDpi, verticalDpi ); + + controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi ); + controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true; + controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag + break; + } + } + + controller.mImpl->RequestRelayout(); + } +} + +float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type ) +{ + float value = 0.0f; + if( NULL != controller.mImpl->mEventData ) + { + switch( type ) + { + case POINT_SIZE: + { + if( NULL != controller.mImpl->mEventData->mPlaceholderFont ) + { + value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize; + } + else + { + // If the placeholder text font size is not set, then return the default font size. + value = controller.GetDefaultFontSize( POINT_SIZE ); + } + break; + } + case PIXEL_SIZE: + { + if( NULL != controller.mImpl->mEventData->mPlaceholderFont ) + { + // Pixel size = Point size * DPI / 72.f + unsigned int horizontalDpi = 0u; + unsigned int verticalDpi = 0u; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.GetDpi( horizontalDpi, verticalDpi ); + + value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f; + } + else + { + // If the placeholder text font size is not set, then return the default font size. + value = controller.GetDefaultFontSize( PIXEL_SIZE ); + } + break; + } + } + return value; + } + + return value; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor ) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mPlaceholderTextColor = textColor; + } + + if( controller.mImpl->IsShowingPlaceholderText() ) + { + controller.mImpl->mModel->mVisualModel->SetTextColor( textColor ); + controller.mImpl->RequestRelayout(); + } +} + +const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mPlaceholderTextColor; + } + + return Color::BLACK; +} + +void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map ) +{ + const Property::Map::SizeType count = map.Count(); + + for( Property::Map::SizeType position = 0; position < count; ++position ) + { + KeyValuePair keyValue = map.GetKeyValue( position ); + Property::Key& key = keyValue.first; + Property::Value& value = keyValue.second; + + if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT ) + { + std::string text = ""; + value.Get( text ); + SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text); + } + else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED ) + { + std::string text = ""; + value.Get( text ); + SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text); + } + else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) + { + Vector4 textColor; + value.Get( textColor ); + if( GetPlaceholderTextColor(controller) != textColor ) + { + SetPlaceholderTextColor(controller, textColor); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) + { + std::string fontFamily = ""; + value.Get( fontFamily ); + SetPlaceholderFontFamily(controller, fontFamily); + } + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) + { + SetFontStyleProperty( &controller, value, Text::FontStyle::PLACEHOLDER ); + } + else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) + { + float pointSize; + value.Get( pointSize ); + if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize) ) + { + SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) + { + float pixelSize; + value.Get( pixelSize ); + if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize) ) + { + SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) + { + bool ellipsis; + value.Get( ellipsis ); + SetPlaceholderTextElideEnabled(controller, ellipsis); + } + } +} + +void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( !controller.mImpl->mEventData->mPlaceholderTextActive.empty() ) + { + map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = controller.mImpl->mEventData->mPlaceholderTextActive; + } + if( !controller.mImpl->mEventData->mPlaceholderTextInactive.empty() ) + { + map[ Text::PlaceHolder::Property::TEXT ] = controller.mImpl->mEventData->mPlaceholderTextInactive; + } + + map[ Text::PlaceHolder::Property::COLOR ] = controller.mImpl->mEventData->mPlaceholderTextColor; + map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(controller); + + Property::Value fontStyleMapGet; + GetFontStyleProperty( &controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER ); + map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; + + // Choose font size : POINT_SIZE or PIXEL_SIZE + if( !controller.mImpl->mEventData->mIsPlaceholderPixelSize ) + { + map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE); + } + else + { + map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE); + } + + if( controller.mImpl->mEventData->mPlaceholderEllipsisFlag ) + { + map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(controller); + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-placeholder-handler.h b/dali-toolkit/internal/text/text-controller-placeholder-handler.h new file mode 100644 index 0000000..273c69b --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-placeholder-handler.h @@ -0,0 +1,69 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H + +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::PlaceholderHandler +{ + static void SetPlaceholderTextElideEnabled(Controller& controller, bool enabled); + static bool IsPlaceholderTextElideEnabled(const Controller& controller); + static void SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text); + static void GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text); + static void SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily); + static const std::string& GetPlaceholderFontFamily(const Controller& controller); + static void SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight); + static bool IsPlaceholderTextFontWeightDefined(const Controller& controller); + static FontWeight GetPlaceholderTextFontWeight(const Controller& controller); + static void SetPlaceholderTextFontWidth(Controller& controller, FontWidth width); + static bool IsPlaceholderTextFontWidthDefined(const Controller& controller); + static FontWidth GetPlaceholderTextFontWidth(const Controller& controller); + static void SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant); + static bool IsPlaceholderTextFontSlantDefined(const Controller& controller); + static FontSlant GetPlaceholderTextFontSlant(const Controller& controller); + static void SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type); + static float GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type ); + static void SetPlaceholderTextColor(Controller& controller, const Vector4& textColor ); + static const Vector4& GetPlaceholderTextColor(const Controller& controller); + static void SetPlaceholderProperty(Controller& controller, const Property::Map& map ); + static void GetPlaceholderProperty(Controller& controller, Property::Map& map); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index ca02bac..31c1edf 100755 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -22,49 +22,29 @@ #include #include #include -#include #include -#include -#include -#include // INTERNAL INCLUDES -#include -#include #include #include #include -#include +#include #include +#include +#include #include -#include namespace { #if defined(DEBUG_ENABLED) - Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif const float MAX_FLOAT = std::numeric_limits::max(); const std::string EMPTY_STRING(""); -const std::string KEY_C_NAME = "c"; -const std::string KEY_V_NAME = "v"; -const std::string KEY_X_NAME = "x"; -const std::string KEY_A_NAME = "a"; -const std::string KEY_INSERT_NAME = "Insert"; - -const char * const PLACEHOLDER_TEXT = "text"; -const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused"; -const char * const PLACEHOLDER_COLOR = "color"; -const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily"; -const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; -const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; -const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; -const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; - float ConvertToEven( float value ) { int intValue(static_cast( value )); @@ -92,44 +72,6 @@ namespace Toolkit namespace Text { -/** - * @brief Adds a new font description run for the selected text. - * - * The new font parameters are added after the call to this method. - * - * @param[in] eventData The event data pointer. - * @param[in] logicalModel The logical model where to add the new font description run. - * @param[out] startOfSelectedText Index to the first selected character. - * @param[out] lengthOfSelectedText Number of selected characters. - */ -FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData, - LogicalModelPtr logicalModel, - CharacterIndex& startOfSelectedText, - Length& lengthOfSelectedText ) -{ - const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition; - - // Get start and end position of selection - startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition; - lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText; - - // Add the font run. - const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); - logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); - - FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); - - fontDescriptionRun.characterRun.characterIndex = startOfSelectedText; - fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText; - - // Recalculate the selection highlight as the metrics may have changed. - eventData->mUpdateLeftSelectionPosition = true; - eventData->mUpdateRightSelectionPosition = true; - eventData->mUpdateHighlightBox = true; - - return fontDescriptionRun; -} - // public : Constructor. ControllerPtr Controller::New() @@ -594,20 +536,12 @@ Vector2 Controller::GetTextFitContentSize() const void Controller::SetPlaceholderTextElideEnabled( bool enabled ) { - mImpl->mEventData->mIsPlaceholderElideEnabled = enabled; - mImpl->mEventData->mPlaceholderEllipsisFlag = true; - - // Update placeholder if there is no text - if( mImpl->IsShowingPlaceholderText() || - ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) - { - ShowPlaceholderText(); - } + PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled); } bool Controller::IsPlaceholderTextElideEnabled() const { - return mImpl->mEventData->mIsPlaceholderElideEnabled; + return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this); } void Controller::SetSelectionEnabled( bool enabled ) @@ -776,39 +710,12 @@ void Controller::GetText( std::string& text ) const void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text ) { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - mImpl->mEventData->mPlaceholderTextInactive = text; - } - else - { - mImpl->mEventData->mPlaceholderTextActive = text; - } - - // Update placeholder if there is no text - if( mImpl->IsShowingPlaceholderText() || - ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) - { - ShowPlaceholderText(); - } - } + PlaceholderHandler::SetPlaceholderText(*this, type, text); } void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - text = mImpl->mEventData->mPlaceholderTextInactive; - } - else - { - text = mImpl->mEventData->mPlaceholderTextActive; - } - } + PlaceholderHandler::GetPlaceholderText(*this, type, text ); } void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) @@ -867,29 +774,12 @@ const std::string& Controller::GetDefaultFontFamily() const void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily; - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str()); - mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty(); - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily); } const std::string& Controller::GetPlaceholderFontFamily() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.family; - } - - return EMPTY_STRING; + return PlaceholderHandler::GetPlaceholderFontFamily(*this); } void Controller::SetDefaultFontWeight( FontWeight weight ) @@ -940,37 +830,17 @@ FontWeight Controller::GetDefaultFontWeight() const void Controller::SetPlaceholderTextFontWeight( FontWeight weight ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight; - mImpl->mEventData->mPlaceholderFont->weightDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight); } bool Controller::IsPlaceholderTextFontWeightDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->weightDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);; } FontWeight Controller::GetPlaceholderTextFontWeight() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight; - } - - return TextAbstraction::FontWeight::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWeight(*this); } void Controller::SetDefaultFontWidth( FontWidth width ) @@ -1021,37 +891,17 @@ FontWidth Controller::GetDefaultFontWidth() const void Controller::SetPlaceholderTextFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width; - mImpl->mEventData->mPlaceholderFont->widthDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width); } bool Controller::IsPlaceholderTextFontWidthDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->widthDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this); } FontWidth Controller::GetPlaceholderTextFontWidth() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.width; - } - - return TextAbstraction::FontWidth::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWidth(*this); } void Controller::SetDefaultFontSlant( FontSlant slant ) @@ -1101,37 +951,17 @@ FontSlant Controller::GetDefaultFontSlant() const void Controller::SetPlaceholderTextFontSlant( FontSlant slant ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; - mImpl->mEventData->mPlaceholderFont->slantDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant); } bool Controller::IsPlaceholderTextFontSlantDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->slantDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this); } FontSlant Controller::GetPlaceholderTextFontSlant() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; - } - - return TextAbstraction::FontSlant::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontSlant(*this); } void Controller::SetDefaultFontSize( float fontSize, FontSizeType type ) @@ -1211,85 +1041,12 @@ float Controller::GetDefaultFontSize( FontSizeType type ) const void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - switch( type ) - { - case POINT_SIZE: - { - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize; - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag - break; - } - case PIXEL_SIZE: - { - // Point size = Pixel size * 72.f / DPI - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi ); - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag - break; - } - } - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type); } float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const { - float value = 0.0f; - if( NULL != mImpl->mEventData ) - { - switch( type ) - { - case POINT_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( POINT_SIZE ); - } - break; - } - case PIXEL_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - // Pixel size = Point size * DPI / 72.f - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( PIXEL_SIZE ); - } - break; - } - } - return value; - } - - return value; + return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type); } void Controller::SetDefaultColor( const Vector4& color ) @@ -1315,26 +1072,12 @@ const Vector4& Controller::GetDefaultColor() const void Controller::SetPlaceholderTextColor( const Vector4& textColor ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mPlaceholderTextColor = textColor; - } - - if( mImpl->IsShowingPlaceholderText() ) - { - mImpl->mModel->mVisualModel->SetTextColor( textColor ); - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextColor(*this, textColor); } const Vector4& Controller::GetPlaceholderTextColor() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mPlaceholderTextColor; - } - - return Color::BLACK; + return PlaceholderHandler::GetPlaceholderTextColor(*this); } void Controller::SetShadowOffset( const Vector2& shadowOffset ) @@ -1581,404 +1324,102 @@ const Vector4& Controller::GetInputColor() const void Controller::SetInputFontFamily( const std::string& fontFamily ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.familyName = fontFamily; - mImpl->mEventData->mInputStyle.isFamilyDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.familyLength = fontFamily.size(); - fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; - memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); - fontDescriptionRun.familyDefined = true; + InputFontHandler::SetInputFontFamily(*this, fontFamily); +} - // The memory allocated for the font family name is freed when the font description is removed from the logical model. +const std::string& Controller::GetInputFontFamily() const +{ + return InputFontHandler::GetInputFontFamily(*this); +} - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } +void Controller::SetInputFontWeight( FontWeight weight ) +{ + InputFontHandler::SetInputFontWeight(*this, weight); +} - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); +bool Controller::IsInputFontWeightDefined() const +{ + return InputFontHandler::IsInputFontWeightDefined(*this); +} - // As the font changes, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } +FontWeight Controller::GetInputFontWeight() const +{ + return InputFontHandler::GetInputFontWeight(*this); } -const std::string& Controller::GetInputFontFamily() const +void Controller::SetInputFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.familyName; - } + InputFontHandler::SetInputFontWidth(*this, width); +} - // Return the default font's family if there is no EventData. - return GetDefaultFontFamily(); +bool Controller::IsInputFontWidthDefined() const +{ + return InputFontHandler::IsInputFontWidthDefined(*this); } -void Controller::SetInputFontWeight( FontWeight weight ) +FontWidth Controller::GetInputFontWidth() const { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.weight = weight; - mImpl->mEventData->mInputStyle.isWeightDefined = true; + return InputFontHandler::GetInputFontWidth(*this); +} - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; +void Controller::SetInputFontSlant( FontSlant slant ) +{ + InputFontHandler::SetInputFontSlant(*this, slant); +} - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); +bool Controller::IsInputFontSlantDefined() const +{ + return InputFontHandler::IsInputFontSlantDefined(*this); +} - fontDescriptionRun.weight = weight; - fontDescriptionRun.weightDefined = true; +FontSlant Controller::GetInputFontSlant() const +{ + return InputFontHandler::GetInputFontSlant(*this); +} - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } +void Controller::SetInputFontPointSize( float size ) +{ + InputFontHandler::SetInputFontPointSize(*this, size); +} - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); +float Controller::GetInputFontPointSize() const +{ + return InputFontHandler::GetInputFontPointSize(*this); +} - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } +void Controller::SetInputLineSpacing( float lineSpacing ) +{ + if( NULL != mImpl->mEventData ) + { + mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing; + mImpl->mEventData->mInputStyle.isLineSpacingDefined = true; } } -bool Controller::IsInputFontWeightDefined() const +float Controller::GetInputLineSpacing() const { - bool defined = false; - if( NULL != mImpl->mEventData ) { - defined = mImpl->mEventData->mInputStyle.isWeightDefined; + return mImpl->mEventData->mInputStyle.lineSpacing; } - return defined; + return 0.f; } -FontWeight Controller::GetInputFontWeight() const +void Controller::SetInputShadowProperties( const std::string& shadowProperties ) { if( NULL != mImpl->mEventData ) { - return mImpl->mEventData->mInputStyle.weight; + mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties; } - - return GetDefaultFontWeight(); } -void Controller::SetInputFontWidth( FontWidth width ) +const std::string& Controller::GetInputShadowProperties() const { if( NULL != mImpl->mEventData ) { - mImpl->mEventData->mInputStyle.width = width; - mImpl->mEventData->mInputStyle.isWidthDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.width = width; - fontDescriptionRun.widthDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -bool Controller::IsInputFontWidthDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWidthDefined; - } - - return defined; -} - -FontWidth Controller::GetInputFontWidth() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.width; - } - - return GetDefaultFontWidth(); -} - -void Controller::SetInputFontSlant( FontSlant slant ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.slant = slant; - mImpl->mEventData->mInputStyle.isSlantDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.slant = slant; - fontDescriptionRun.slantDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -bool Controller::IsInputFontSlantDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isSlantDefined; - } - - return defined; -} - -FontSlant Controller::GetInputFontSlant() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.slant; - } - - return GetDefaultFontSlant(); -} - -void Controller::SetInputFontPointSize( float size ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.size = size; - mImpl->mEventData->mInputStyle.isSizeDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.size = static_cast( size * 64.f ); - fontDescriptionRun.sizeDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -float Controller::GetInputFontPointSize() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.size; - } - - // Return the default font's point size if there is no EventData. - return GetDefaultFontSize( Text::Controller::POINT_SIZE ); -} - -void Controller::SetInputLineSpacing( float lineSpacing ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing; - mImpl->mEventData->mInputStyle.isLineSpacingDefined = true; - } -} - -float Controller::GetInputLineSpacing() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.lineSpacing; - } - - return 0.f; -} - -void Controller::SetInputShadowProperties( const std::string& shadowProperties ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties; - } -} - -const std::string& Controller::GetInputShadowProperties() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.shadowProperties; - } + return mImpl->mEventData->mInputStyle.shadowProperties; + } return EMPTY_STRING; } @@ -2433,107 +1874,12 @@ void Controller::GetHiddenInputOption(Property::Map& options ) void Controller::SetPlaceholderProperty( const Property::Map& map ) { - const Property::Map::SizeType count = map.Count(); - - for( Property::Map::SizeType position = 0; position < count; ++position ) - { - KeyValuePair keyValue = map.GetKeyValue( position ); - Property::Key& key = keyValue.first; - Property::Value& value = keyValue.second; - - if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT ) - { - std::string text = ""; - value.Get( text ); - SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED ) - { - std::string text = ""; - value.Get( text ); - SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) - { - Vector4 textColor; - value.Get( textColor ); - if( GetPlaceholderTextColor() != textColor ) - { - SetPlaceholderTextColor( textColor ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) - { - std::string fontFamily = ""; - value.Get( fontFamily ); - SetPlaceholderFontFamily( fontFamily ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) - { - SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) - { - float pointSize; - value.Get( pointSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) ) - { - SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) - { - float pixelSize; - value.Get( pixelSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) ) - { - SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) - { - bool ellipsis; - value.Get( ellipsis ); - SetPlaceholderTextElideEnabled( ellipsis ); - } - } + PlaceholderHandler::SetPlaceholderProperty(*this, map); } void Controller::GetPlaceholderProperty( Property::Map& map ) { - if( NULL != mImpl->mEventData ) - { - if( !mImpl->mEventData->mPlaceholderTextActive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive; - } - if( !mImpl->mEventData->mPlaceholderTextInactive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive; - } - - map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor; - map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(); - - Property::Value fontStyleMapGet; - GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER ); - map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; - - // Choose font size : POINT_SIZE or PIXEL_SIZE - if( !mImpl->mEventData->mIsPlaceholderPixelSize ) - { - map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ); - } - else - { - map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ); - } - - if( mImpl->mEventData->mPlaceholderEllipsisFlag ) - { - map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(); - } - } + PlaceholderHandler::GetPlaceholderProperty(*this, map); } Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection() @@ -2783,418 +2129,38 @@ void Controller::ProcessInputStyleChangedSignals() void Controller::KeyboardFocusGainEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( ( EventData::INACTIVE == mImpl->mEventData->mState ) || - ( EventData::INTERRUPTED == mImpl->mEventData->mState ) ) - { - mImpl->ChangeState( EventData::EDITING ); - mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered. - mImpl->mEventData->mUpdateInputStyle = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - mImpl->NotifyInputMethodContextMultiLineStatus(); - if( mImpl->IsShowingPlaceholderText() ) - { - // Show alternative placeholder-text when editing - ShowPlaceholderText(); - } - - mImpl->RequestRelayout(); - } + EventHandler::KeyboardFocusGainEvent(*this); } void Controller::KeyboardFocusLostEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( EventData::INTERRUPTED != mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::INACTIVE ); - - if( !mImpl->IsShowingRealText() ) - { - // Revert to regular placeholder-text when not editing - ShowPlaceholderText(); - } - } - } - mImpl->RequestRelayout(); + EventHandler::KeyboardFocusLostEvent(*this); } bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" ); - - bool textChanged = false; - bool relayoutNeeded = false; + return EventHandler::KeyEvent(*this, keyEvent); +} - if( ( NULL != mImpl->mEventData ) && - ( keyEvent.GetState() == KeyEvent::DOWN ) ) - { - int keyCode = keyEvent.GetKeyCode(); - const std::string& keyString = keyEvent.GetKeyString(); - const std::string keyName = keyEvent.GetKeyName(); +void Controller::TapEvent( unsigned int tapCount, float x, float y ) +{ + EventHandler::TapEvent(*this, tapCount, x, y); +} - const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); +void Controller::PanEvent( GestureState state, const Vector2& displacement ) +{ + EventHandler::PanEvent(*this, state, displacement); +} - // Pre-process to separate modifying events from non-modifying input events. - if( isNullKey ) - { - // In some platforms arrive key events with no key code. - // Do nothing. - return false; - } - else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) - { - // Do nothing - return false; - } - else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) ) - { - // If don't have any text, do nothing. - if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) - { - return false; - } +void Controller::LongPressEvent( GestureState state, float x, float y ) +{ + EventHandler::LongPressEvent(*this, state, x, y); +} - uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition; - uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition ); - uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines(); - - // Logic to determine whether this text control will lose focus or not. - if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) ) - { - // Release the active highlight. - if( mImpl->mEventData->mState == EventData::SELECTING ) - { - mImpl->ChangeState( EventData::EDITING ); - - // Update selection position. - mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->RequestRelayout(); - } - return false; - } - - mImpl->mEventData->mCheckScrollAmount = true; - Event event( Event::CURSOR_KEY_EVENT ); - event.p1.mInt = keyCode; - event.p2.mBool = keyEvent.IsShiftModifier(); - mImpl->mEventData->mEventQueue.push_back( event ); - - // Will request for relayout. - relayoutNeeded = true; - } - else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) - { - // Left or Right Control key event is received before Ctrl-C/V/X key event is received - // If not handle it here, any selected text will be deleted - - // Do nothing - return false; - } - else if ( keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier()) - { - bool consumed = false; - if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME) - { - // Ctrl-C or Ctrl+Insert to copy the selected text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY ); - consumed = true; - } - else if (keyName == KEY_V_NAME) - { - // Ctrl-V to paste the copied text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE ); - consumed = true; - } - else if (keyName == KEY_X_NAME) - { - // Ctrl-X to cut the selected text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT ); - consumed = true; - } - else if (keyName == KEY_A_NAME) - { - // Ctrl-A to select All the text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL ); - consumed = true; - } - return consumed; - } - else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) || - ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) ) - { - textChanged = DeleteEvent( keyCode ); - - // Will request for relayout. - relayoutNeeded = true; - } - else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) || - IsKey( keyEvent, Dali::DALI_KEY_MENU ) || - IsKey( keyEvent, Dali::DALI_KEY_HOME ) ) - { - // Power key/Menu/Home key behaviour does not allow edit mode to resume. - mImpl->ChangeState( EventData::INACTIVE ); - - // Will request for relayout. - relayoutNeeded = true; - - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - } - else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) ) - { - // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled - // and a character is typed after the type of a upper case latin character. - - // Do nothing. - return false; - } - else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) ) - { - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - // Do nothing. - return false; - } - else - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() ); - if (!IsEditable()) return false; - - if( !keyString.empty() ) - { - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - InsertText( keyString, COMMIT ); - - textChanged = true; - - // Will request for relayout. - relayoutNeeded = true; - } - - } - - if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) && - ( mImpl->mEventData->mState != EventData::INACTIVE ) && - ( !isNullKey ) && - ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) && - ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) && - ( Dali::DALI_KEY_VOLUME_UP != keyCode ) && - ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) ) - { - // Should not change the state if the key is the shift send by the InputMethodContext. - // Otherwise, when the state is SELECTING the text controller can't send the right - // surrounding info to the InputMethodContext. - mImpl->ChangeState( EventData::EDITING ); - - // Will request for relayout. - relayoutNeeded = true; - } - - if( relayoutNeeded ) - { - mImpl->RequestRelayout(); - } - } - - if( textChanged && - ( NULL != mImpl->mEditableControlInterface ) ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); - } - - return true; -} - -void Controller::TapEvent( unsigned int tapCount, float x, float y ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" ); - - if( NULL != mImpl->mEventData ) - { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState ); - EventData::State state( mImpl->mEventData->mState ); - bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field - - if( mImpl->IsClipboardVisible() ) - { - if( EventData::INACTIVE == state || EventData::EDITING == state) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - } - relayoutNeeded = true; - } - else if( 1u == tapCount ) - { - if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required. - } - - if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - relayoutNeeded = true; - } - else - { - if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() ) - { - // Hide placeholder text - ResetText(); - } - - if( EventData::INACTIVE == state ) - { - mImpl->ChangeState( EventData::EDITING ); - } - else if( !mImpl->IsClipboardEmpty() ) - { - mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); - } - relayoutNeeded = true; - } - } - else if( 2u == tapCount ) - { - if( mImpl->mEventData->mSelectionEnabled && - mImpl->IsShowingRealText() ) - { - relayoutNeeded = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } - - // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated - if( relayoutNeeded ) - { - Event event( Event::TAP_EVENT ); - event.p1.mUint = tapCount; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - } - - // Reset keyboard as tap event has occurred. - mImpl->ResetInputMethodContext(); -} - -void Controller::PanEvent( GestureState state, const Vector2& displacement ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" ); - - if( NULL != mImpl->mEventData ) - { - Event event( Event::PAN_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = displacement.x; - event.p3.mFloat = displacement.y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } -} - -void Controller::LongPressEvent( GestureState state, float x, float y ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" ); - - if( ( state == GestureState::STARTED ) && - ( NULL != mImpl->mEventData ) ) - { - // The 1st long-press on inactive text-field is treated as tap - if( EventData::INACTIVE == mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::EDITING ); - - Event event( Event::TAP_EVENT ); - event.p1.mUint = 1; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - else if( !mImpl->IsShowingRealText() ) - { - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); - } - else if( !mImpl->IsClipboardVisible() ) - { - // Reset the InputMethodContext to commit the pre-edit before selecting the text. - mImpl->ResetInputMethodContext(); - - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); - - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } -} - -void Controller::SelectEvent( float x, float y, SelectionType selectType ) -{ - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); - - if( NULL != mImpl->mEventData ) - { - if( selectType == SelectionType::ALL ) - { - Event event( Event::SELECT_ALL ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else if( selectType == SelectionType::NONE ) - { - Event event( Event::SELECT_NONE ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else - { - Event event( Event::SELECT ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - } - - mImpl->mEventData->mCheckScrollAmount = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - mImpl->RequestRelayout(); - } -} +void Controller::SelectEvent( float x, float y, SelectionType selectType ) +{ + EventHandler::SelectEvent(*this, x, y, selectType); +} void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end) { @@ -3214,144 +2180,34 @@ Uint32Pair Controller::GetTextSelectionRange() const return mImpl->GetTextSelectionRange(); } -InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) +void Controller::SelectWholeText() { - // Whether the text needs to be relaid-out. - bool requestRelayout = false; - - // Whether to retrieve the text and cursor position to be sent to the InputMethodContext. - bool retrieveText = false; - bool retrieveCursor = false; - - switch( inputMethodContextEvent.eventName ) - { - case InputMethodContext::COMMIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRE_EDIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::DELETE_SURROUNDING: - { - const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset, - inputMethodContextEvent.numberOfChars, - DONT_UPDATE_INPUT_STYLE ); - - if( textDeleted ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - requestRelayout = true; - } - break; - } - case InputMethodContext::GET_SURROUNDING: - { - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRIVATE_COMMAND: - { - // PRIVATECOMMAND event is just for getting the private command message - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::VOID: - { - // do nothing - break; - } - } // end switch - - if( requestRelayout ) - { - mImpl->mOperationsPending = ALL_OPERATIONS; - mImpl->RequestRelayout(); - } - - std::string text; - CharacterIndex cursorPosition = 0u; - Length numberOfWhiteSpaces = 0u; - - if( retrieveCursor ) - { - numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u ); - - cursorPosition = mImpl->GetLogicalCursorPosition(); - - if( cursorPosition < numberOfWhiteSpaces ) - { - cursorPosition = 0u; - } - else - { - cursorPosition -= numberOfWhiteSpaces; - } - } - - if( retrieveText ) - { - if( !mImpl->IsShowingPlaceholderText() ) - { - // Retrieves the normal text string. - mImpl->GetText( numberOfWhiteSpaces, text ); - } - else - { - // When the current text is Placeholder Text, the surrounding text should be empty string. - // It means DALi should send empty string ("") to IME. - text = ""; - } - } + SelectEvent( 0.f, 0.f, SelectionType::ALL ); +} - InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); +void Controller::SelectNone() +{ + SelectEvent( 0.f, 0.f, SelectionType::NONE ); +} - if( requestRelayout && - ( NULL != mImpl->mEditableControlInterface ) ) +string Controller::GetSelectedText() const +{ + string text; + if( EventData::SELECTING == mImpl->mEventData->mState ) { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); + mImpl->RetrieveSelection( text, false ); } + return text; +} - return callbackData; +InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) +{ + return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent); } void Controller::PasteClipboardItemEvent() { - // Retrieve the clipboard contents first - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - std::string stringToPaste( notifier.GetContent() ); - - // Commit the current pre-edit text; the contents of the clipboard should be appended - mImpl->ResetInputMethodContext(); - - // Temporary disable hiding clipboard - mImpl->SetClipboardHideEnable( false ); - - // Paste - PasteText( stringToPaste ); - - mImpl->SetClipboardHideEnable( true ); + EventHandler::PasteClipboardItemEvent(*this); } // protected : Inherit from Text::Decorator::ControllerInterface. @@ -3385,138 +2241,14 @@ void Controller::SetEditable( bool editable ) void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" ); - - if( NULL != mImpl->mEventData ) - { - switch( handleType ) - { - case GRAB_HANDLE: - { - Event event( Event::GRAB_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case LEFT_SELECTION_HANDLE: - { - Event event( Event::LEFT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case RIGHT_SELECTION_HANDLE: - { - Event event( Event::RIGHT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case LEFT_SELECTION_HANDLE_MARKER: - case RIGHT_SELECTION_HANDLE_MARKER: - { - // Markers do not move the handles. - break; - } - case HANDLE_TYPE_COUNT: - { - DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); - } - } - - mImpl->RequestRelayout(); - } + EventHandler::DecorationEvent(*this, handleType, state, x, y); } // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface. void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button ) { - if( NULL == mImpl->mEventData ) - { - return; - } - - switch( button ) - { - case Toolkit::TextSelectionPopup::CUT: - { - if (!IsEditable()) return; - mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text - mImpl->mOperationsPending = ALL_OPERATIONS; - - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - mImpl->RequestRelayout(); - - if( NULL != mImpl->mEditableControlInterface ) - { - mImpl->mEditableControlInterface->TextChanged(); - } - break; - } - case Toolkit::TextSelectionPopup::COPY: - { - mImpl->SendSelectionToClipboard( false ); // Text not modified - - mImpl->mEventData->mUpdateCursorPosition = true; - - mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup - break; - } - case Toolkit::TextSelectionPopup::PASTE: - { - mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item - break; - } - case Toolkit::TextSelectionPopup::SELECT: - { - const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); - - if( mImpl->mEventData->mSelectionEnabled ) - { - // Creates a SELECT event. - SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE ); - } - break; - } - case Toolkit::TextSelectionPopup::SELECT_ALL: - { - // Creates a SELECT_ALL event - SelectEvent( 0.f, 0.f, SelectionType::ALL ); - break; - } - case Toolkit::TextSelectionPopup::CLIPBOARD: - { - mImpl->ShowClipboard(); - break; - } - case Toolkit::TextSelectionPopup::NONE: - { - // Nothing to do. - break; - } - } + EventHandler::TextPopupButtonTouched(*this, button); } void Controller::DisplayTimeExpired() @@ -3926,16 +2658,6 @@ bool Controller::RemoveSelectedText() return textRemoved; } -std::string Controller::GetSelectedText() -{ - std::string text; - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - mImpl->RetrieveSelection( text, false ); - } - return text; -} - // private : Relayout. bool Controller::DoRelayout( const Size& size, @@ -4148,163 +2870,27 @@ void Controller::CalculateVerticalOffset( const Size& controlSize ) void Controller::ProcessModifyEvents() { - Vector& events = mImpl->mModifyEvents; - - if( 0u == events.Count() ) - { - // Nothing to do. - return; - } - - for( Vector::ConstIterator it = events.Begin(), - endIt = events.End(); - it != endIt; - ++it ) - { - const ModifyEvent& event = *it; - - if( ModifyEvent::TEXT_REPLACED == event.type ) - { - // A (single) replace event should come first, otherwise we wasted time processing NOOP events - DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" ); - - TextReplacedEvent(); - } - else if( ModifyEvent::TEXT_INSERTED == event.type ) - { - TextInsertedEvent(); - } - else if( ModifyEvent::TEXT_DELETED == event.type ) - { - // Placeholder-text cannot be deleted - if( !mImpl->IsShowingPlaceholderText() ) - { - TextDeletedEvent(); - } - } - } - - if( NULL != mImpl->mEventData ) - { - // When the text is being modified, delay cursor blinking - mImpl->mEventData->mDecorator->DelayCursorBlink(); - - // Update selection position after modifying the text - mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - } - - // DISCARD temporary text - events.Clear(); + EventHandler::ProcessModifyEvents(*this); } void Controller::TextReplacedEvent() { - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextReplacedEvent(*this); } void Controller::TextInsertedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - mImpl->mEventData->mCheckScrollAmount = true; - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model; TODO - Optimize this - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextInsertedEvent(*this); } void Controller::TextDeletedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - if (!IsEditable()) return; - - mImpl->mEventData->mCheckScrollAmount = true; - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model; TODO - Optimize this - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextDeletedEvent(*this); } bool Controller::DeleteEvent( int keyCode ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode ); - - bool removed = false; - - if( NULL == mImpl->mEventData ) - { - return removed; - } - - if (!IsEditable()) return false; - - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - removed = RemoveSelectedText(); - } - else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) ) - { - // Remove the character before the current cursor position - removed = RemoveText( -1, - 1, - UPDATE_INPUT_STYLE ); - } - else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) - { - // Remove the character after the current cursor position - removed = RemoveText( 0, - 1, - UPDATE_INPUT_STYLE ); - } - - if( removed ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - } - - return removed; + return EventHandler::DeleteEvent(*this, keyCode); } // private : Helpers. @@ -4486,23 +3072,20 @@ Actor Controller::CreateBackgroundActor() // private : Private contructors & copy operator. Controller::Controller() -: mImpl( NULL ) +: Controller(nullptr, nullptr, nullptr) { - mImpl = new Controller::Impl( nullptr, nullptr, nullptr ); } Controller::Controller( ControlInterface* controlInterface ) +:Controller( controlInterface, nullptr, nullptr) { - mImpl = new Controller::Impl( controlInterface, NULL, NULL ); } Controller::Controller( ControlInterface* controlInterface, EditableControlInterface* editableControlInterface, SelectableControlInterface* selectableControlInterface ) +: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface)) { - mImpl = new Controller::Impl( controlInterface, - editableControlInterface, - selectableControlInterface ); } // The copy constructor and operator are left unimplemented. diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index e523dd2..54444b1 100755 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_TEXT_CONTROLLER_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -1506,6 +1506,21 @@ public: // Text-input Event Queuing. Uint32Pair GetTextSelectionRange() const; /** + * @copydoc Text::SelectableControlInterface::SelectWholeText() + */ + void SelectWholeText(); + + /** + * @copydoc Text::SelectableControlInterface::SelectNone() + */ + void SelectNone(); + + /** + * @copydoc Text::SelectableControlInterface::GetSelectedText() + */ + string GetSelectedText() const; + + /** * @copydoc Text::EditableControlInterface::IsEditable() */ virtual bool IsEditable() const; @@ -1543,13 +1558,6 @@ public: // Text-input Event Queuing. */ Actor CreateBackgroundActor(); - /** - * @brief Retrive Selected text. - * - * @return The seleced text. - */ - std::string GetSelectedText(); - protected: // Inherit from Text::Decorator::ControllerInterface. /** @@ -1743,6 +1751,10 @@ public: private: + struct EventHandler; + struct InputFontHandler; + struct PlaceholderHandler; + Impl* mImpl; }; diff --git a/dali-toolkit/internal/text/text-run-container.h b/dali-toolkit/internal/text/text-run-container.h index 3b54d5c..5af8c55 100644 --- a/dali-toolkit/internal/text/text-run-container.h +++ b/dali-toolkit/internal/text/text-run-container.h @@ -178,6 +178,9 @@ void UpdateCharacterRuns( CharacterIndex index, { T& run = *it; + if (run.characterRun.numberOfCharacters == 0) + continue; + const CharacterIndex lastRunIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u; if( lastRunIndex < index ) @@ -240,6 +243,9 @@ void UpdateCharacterRuns( CharacterIndex index, { T& run = *it; + if (run.characterRun.numberOfCharacters == 0) + continue; + // Update the number of characters of the style run. if( ( 0u == index ) && ( 0u == run.characterRun.characterIndex ) ) diff --git a/dali-toolkit/internal/text/text-selectable-control-interface.h b/dali-toolkit/internal/text/text-selectable-control-interface.h index fe70abb..65a35ca 100644 --- a/dali-toolkit/internal/text/text-selectable-control-interface.h +++ b/dali-toolkit/internal/text/text-selectable-control-interface.h @@ -25,6 +25,7 @@ namespace Toolkit { using Uint32Pair = std::pair; +using string = std::string; namespace Text { @@ -52,6 +53,22 @@ public: * @return pair contains start and end positions. */ virtual Uint32Pair GetTextSelectionRange() const = 0; + + /** + * @brief Called to select the whole texts. + */ + virtual void SelectWholeText() = 0; + + /** + * @brief Called to unselect the whole texts. + */ + virtual void SelectNone() = 0; + + /** + * @brief Retrive Selected text. + * @return The seletced text. + */ + virtual string GetSelectedText() const = 0; }; } // namespace Text diff --git a/dali-toolkit/public-api/controls/control.h b/dali-toolkit/public-api/controls/control.h index 7d71948..7720d13 100644 --- a/dali-toolkit/public-api/controls/control.h +++ b/dali-toolkit/public-api/controls/control.h @@ -463,7 +463,6 @@ public: // Intended for control developers * * @SINCE_1_0.0 * @param[in] implementation The implementation for this control - * @return A handle to a newly allocated Dali resource * @note Should NOT be called to create a handle from the implementation. As stated, this allocates a NEW Dali resource. */ explicit Control(Internal::Control& implementation); diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp index b51f9ab..b7dc35f 100644 --- a/dali-toolkit/public-api/dali-toolkit-version.cpp +++ b/dali-toolkit/public-api/dali-toolkit-version.cpp @@ -29,7 +29,7 @@ namespace Toolkit { const unsigned int TOOLKIT_MAJOR_VERSION = 1; const unsigned int TOOLKIT_MINOR_VERSION = 9; -const unsigned int TOOLKIT_MICRO_VERSION = 33; +const unsigned int TOOLKIT_MICRO_VERSION = 34; const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__; #ifdef DEBUG_ENABLED diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index e00bcdc..482b4d9 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -1,6 +1,6 @@ Name: dali2-toolkit Summary: Dali 3D engine Toolkit -Version: 1.9.33 +Version: 1.9.34 Release: 1 Group: System/Libraries License: Apache-2.0 and BSD-3-Clause and MIT