From: Victor Cebollada Date: Wed, 27 Jul 2016 06:10:17 +0000 (+0100) Subject: Add Text input style changed signal. X-Git-Tag: dali_1.2.2~4^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=6ae9cd5f03bd0a8393eebf3cfb4508cab7fd3ede Add Text input style changed signal. * The TextEditor and the TextField can notify through this signal any change in the input style. Change-Id: I2c00a09545b0fa3bdf2e628b5ef7ab2c5fa0179b Signed-off-by: Victor Cebollada --- diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 0db0538..8d01fa3 100644 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -57,6 +57,7 @@ SET(TC_SOURCES # Append list of test harness files (Won't get parsed for test cases) LIST(APPEND TC_SOURCES + dali-toolkit-test-utils/toolkit-adaptor.cpp dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp dali-toolkit-test-utils/toolkit-application.cpp dali-toolkit-test-utils/toolkit-bitmap-loader.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h new file mode 100644 index 0000000..5e71771 --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h @@ -0,0 +1,91 @@ +#ifndef __DALI_TOOLKIT_ADAPTOR_IMPL_H__ +#define __DALI_TOOLKIT_ADAPTOR_IMPL_H__ + +/* + * Copyright (c) 2016 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 + +namespace Dali +{ +class EglInterface; +class DisplayConnection; +class ThreadSynchronizationInterface; + +namespace Integration +{ + +class GlAbstraction; + +} // namespace Integration + +class TestRenderSurface : public RenderSurface +{ +public: + virtual PositionSize GetPositionSize() const { PositionSize size; return size; } + + virtual void InitializeEgl( EglInterface& egl ) {} + + virtual void CreateEglSurface( EglInterface& egl ) {} + + virtual void DestroyEglSurface( EglInterface& egl ) {} + + virtual bool ReplaceEGLSurface( EglInterface& egl ) { return false; } + + virtual void MoveResize( Dali::PositionSize positionSize ) {} + + virtual void SetViewMode( ViewMode viewMode ) {} + + virtual void StartRender() {} + + virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) { return false; } + + virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface ) {} + + virtual void StopRender() {} + + virtual void ReleaseLock() {} + + virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) {} + + virtual RenderSurface::Type GetSurfaceType() { return RenderSurface::ECORE_RENDER_SURFACE; } +}; + +namespace Internal +{ +namespace Adaptor +{ + +class Adaptor: public BaseObject +{ +public: + static Dali::Adaptor& Get(); + Adaptor(); + ~Adaptor(); + +public: + static Dali::RenderSurface& GetSurface(); + static Dali::Adaptor::AdaptorSignalType& AdaptorSignal(); + static bool mAvailable; + static Vector mCallbacks; +}; + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali + +#endif // __DALI_TOOLKIT_ADAPTOR_IMPL_H__ diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp index 4e884e0..4b25c5d 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -19,74 +19,24 @@ #include #include -#include -namespace Dali -{ - -class EglInterface; -class DisplayConnection; -class ThreadSynchronizationInterface; - -namespace Integration -{ +#include -class GlAbstraction; - -} // namespace Integration - -class TestRenderSurface : public RenderSurface +namespace Dali { -public: - virtual PositionSize GetPositionSize() const { PositionSize size; return size; } - - virtual void InitializeEgl( EglInterface& egl ) {} - - virtual void CreateEglSurface( EglInterface& egl ) {} - - virtual void DestroyEglSurface( EglInterface& egl ) {} - - virtual bool ReplaceEGLSurface( EglInterface& egl ) { return false; } - - virtual void MoveResize( Dali::PositionSize positionSize ) {} - - virtual void SetViewMode( ViewMode viewMode ) {} - - virtual void StartRender() {} - - virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) { return false; } - - virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface ) {} - - virtual void StopRender() {} - - virtual void ReleaseLock() {} - - virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) {} - - virtual RenderSurface::Type GetSurfaceType() { return RenderSurface::ECORE_RENDER_SURFACE; } -}; namespace Internal { namespace Adaptor { -class Adaptor: public BaseObject -{ -public: - static Dali::Adaptor& Get(); - Adaptor(); - ~Adaptor(); - -public: - static Dali::RenderSurface& GetSurface(); - static Dali::Adaptor::AdaptorSignalType& AdaptorSignal(); -}; +bool Adaptor::mAvailable = false; +Vector Adaptor::mCallbacks = Vector(); Dali::Adaptor& Adaptor::Get() { Dali::Adaptor* adaptor = new Dali::Adaptor; + Adaptor::mAvailable = true; return *adaptor; } @@ -102,12 +52,8 @@ Dali::Adaptor::AdaptorSignalType& Adaptor::AdaptorSignal() return *signal; } -} -} -} - -namespace Dali -{ +} // namespace Adaptor +} // namespace Internal Adaptor& Adaptor::New( Window window ) { @@ -151,7 +97,34 @@ void Adaptor::Stop() bool Adaptor::AddIdle( CallbackBase* callback ) { - return false; + const bool isAvailable = IsAvailable(); + + if( isAvailable ) + { + Internal::Adaptor::Adaptor::mCallbacks.PushBack( callback ); + } + + return isAvailable; +} + +void Adaptor::RemoveIdle( CallbackBase* callback ) +{ + const bool isAvailable = IsAvailable(); + + if( isAvailable ) + { + for( Vector::Iterator it = Internal::Adaptor::Adaptor::mCallbacks.Begin(), + endIt = Internal::Adaptor::Adaptor::mCallbacks.End(); + it != endIt; + ++it ) + { + if( callback == *it ) + { + Internal::Adaptor::Adaptor::mCallbacks.Remove( it ); + return; + } + } + } } void Adaptor::ReplaceSurface( Any nativeWindow, Dali::RenderSurface& surface ) @@ -198,7 +171,7 @@ Adaptor& Adaptor::Get() bool Adaptor::IsAvailable() { - return false; + return Internal::Adaptor::Adaptor::mAvailable; } void Adaptor::NotifySceneCreated() diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h index 384c22b..5cc5bef 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_TEST_APPLICATION_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -21,6 +21,8 @@ // INTERNAL INCLUDES #include #include +#include +#include namespace Dali { @@ -60,6 +62,39 @@ public: //return mOrientation; //} + /** + * @brief Creates an adaptor implementation for those controls like the + * text-field and the text-editor which connects a callback to the idle signal. + */ + void CreateAdaptor() + { + Adaptor::Get(); + } + + /** + * @brief Executes the idle callbacks. + * + * Some controls like the text-field and the text-editor connect callbacks to the + * idle signal. + */ + void RunIdles() + { + if( Adaptor::IsAvailable() ) + { + for( Vector::Iterator it = Internal::Adaptor::Adaptor::mCallbacks.Begin(), + endIt = Internal::Adaptor::Adaptor::mCallbacks.End(); + it != endIt; + ++it ) + { + CallbackBase* callback = *it; + + CallbackBase::Execute( *callback ); + } + + Internal::Adaptor::Adaptor::mCallbacks.Clear(); + } + } + private: //ToolkitOrientation mOrientation; }; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp index dfc5c86..e9dd5e8 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -92,7 +94,26 @@ const float TO_SECONDS = 1.f / TO_MILLISECONDS; const float SCROLL_THRESHOLD = 10.f; const float SCROLL_SPEED = 300.f; +const unsigned int DEFAULT_FONT_SIZE = 1152u; +const std::string DEFAULT_FONT_DIR( "/resources/fonts" ); + static bool gTextChangedCallBackCalled; +static bool gInputStyleChangedCallbackCalled; +static Dali::Toolkit::TextEditor::InputStyle::Mask gInputStyleMask; + +struct CallbackFunctor +{ + CallbackFunctor(bool* callbackFlag) + : mCallbackFlag( callbackFlag ) + { + } + + void operator()() + { + *mCallbackFlag = true; + } + bool* mCallbackFlag; +}; static void TestTextChangedCallback( TextEditor control ) { @@ -101,6 +122,14 @@ static void TestTextChangedCallback( TextEditor control ) gTextChangedCallBackCalled = true; } +static void TestInputStyleChangedCallback( TextEditor control, TextEditor::InputStyle::Mask mask ) +{ + tet_infoline(" TestInputStyleChangedCallback"); + + gInputStyleChangedCallbackCalled = true; + gInputStyleMask = mask; +} + // Generate a TapGestureEvent to send to Core. Integration::TapGestureEvent GenerateTap( Gesture::State state, @@ -485,11 +514,16 @@ int utcDaliTextEditorTextChangedP(void) Stage::GetCurrent().Add( editor ); - editor.TextChangedSignal().Connect(&TestTextChangedCallback); + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + editor.TextChangedSignal().Connect( &TestTextChangedCallback ); + bool textChangedSignal = false; + editor.ConnectSignal( testTracker, "textChanged", CallbackFunctor(&textChangedSignal) ); gTextChangedCallBackCalled = false; editor.SetProperty( TextEditor::Property::TEXT, "ABC" ); DALI_TEST_CHECK( gTextChangedCallBackCalled ); + DALI_TEST_CHECK( textChangedSignal ); application.SendNotification(); @@ -502,6 +536,464 @@ int utcDaliTextEditorTextChangedP(void) END_TEST; } +int utcDaliTextEditorInputStyleChanged01(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorInputStyleChanged01"); + + // The text-editor emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation. + // This creates an implementation of the adaptor stub and a queue of idle callbacks. + application.CreateAdaptor(); + + // Load some fonts. + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.SetDpi( 93u, 93u ); + + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE ); + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE ); + + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + + editor.SetSize( 300.f, 50.f ); + editor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true ); + editor.SetProperty( TextEditor::Property::TEXT, "Hello world demo" ); + + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + editor.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback ); + bool inputStyleChangedSignal = false; + editor.ConnectSignal( testTracker, "inputStyleChanged", CallbackFunctor(&inputStyleChangedSignal) ); + + Stage::GetCurrent().Add( editor ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 18.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 18.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextEditor::InputStyle::FONT_FAMILY | TextEditor::InputStyle::POINT_SIZE ), TEST_LOCATION ); + + const std::string fontFamily = editor.GetProperty( TextEditor::Property::INPUT_FONT_FAMILY ).Get(); + DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION ); + + const float pointSize = editor.GetProperty( TextEditor::Property::INPUT_POINT_SIZE ).Get(); + DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 43.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 43.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextEditor::InputStyle::COLOR ), TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 88.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 88.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextEditor::InputStyle::COLOR | TextEditor::InputStyle::FONT_STYLE ), TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + + const std::string style = editor.GetProperty( TextEditor::Property::INPUT_FONT_STYLE ).Get(); + DALI_TEST_EQUALS( style, "{\"weight\":\"bold\"}", TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 115.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 115.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 164.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 164.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextEditor::InputStyle::FONT_STYLE ), TEST_LOCATION ); + + const std::string style = editor.GetProperty( TextEditor::Property::INPUT_FONT_STYLE ).Get(); + DALI_TEST_CHECK( style.empty() ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 191.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 191.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + END_TEST; +} + +int utcDaliTextEditorInputStyleChanged02(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorInputStyleChanged02"); + + // The text-editor emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation. + // This creates an implementation of the adaptor stub and a queue of idle callbacks. + application.CreateAdaptor(); + + // Load some fonts. + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.SetDpi( 93u, 93u ); + + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE ); + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE ); + + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + + editor.SetSize( 300.f, 50.f ); + editor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true ); + editor.SetProperty( TextEditor::Property::TEXT, "He llo world demo" ); + + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + editor.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback ); + bool inputStyleChangedSignal = false; + editor.ConnectSignal( testTracker, "inputStyleChanged", CallbackFunctor(&inputStyleChangedSignal) ); + + Stage::GetCurrent().Add( editor ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 53.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextEditor::InputStyle::FONT_FAMILY | + TextEditor::InputStyle::POINT_SIZE | + TextEditor::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION ); + + const std::string fontFamily = editor.GetProperty( TextEditor::Property::INPUT_FONT_FAMILY ).Get(); + DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION ); + + const float pointSize = editor.GetProperty( TextEditor::Property::INPUT_POINT_SIZE ).Get(); + DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextEditor::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLUE, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextEditor::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + editor.SetProperty( TextEditor::Property::INPUT_COLOR, Color::YELLOW ); + + editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, "{\"weight\":\"thin\",\"width\":\"condensed\",\"slant\":\"italic\"}" ); + editor.SetProperty( TextEditor::Property::INPUT_POINT_SIZE, 20.f ); + editor.SetProperty( TextEditor::Property::INPUT_LINE_SPACING, 5.f ); + + editor.SetProperty( TextEditor::Property::INPUT_UNDERLINE, "underline" ); + editor.SetProperty( TextEditor::Property::INPUT_SHADOW, "shadow" ); + editor.SetProperty( TextEditor::Property::INPUT_EMBOSS, "emboss" ); + editor.SetProperty( TextEditor::Property::INPUT_OUTLINE, "outline" ); + + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 63.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 63.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextEditor::InputStyle::COLOR | + TextEditor::InputStyle::POINT_SIZE | + TextEditor::InputStyle::FONT_STYLE | + TextEditor::InputStyle::LINE_SPACING | + TextEditor::InputStyle::UNDERLINE | + TextEditor::InputStyle::SHADOW | + TextEditor::InputStyle::EMBOSS | + TextEditor::InputStyle::OUTLINE ), + TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextEditor::InputStyle::NONE; + inputStyleChangedSignal = false; + + editor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVuSerif" ); + editor.SetProperty( TextEditor::Property::FONT_STYLE, "{\"weight\":\"black\",\"width\":\"expanded\",\"slant\":\"oblique\"}" ); + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextEditor::InputStyle::COLOR | + TextEditor::InputStyle::POINT_SIZE | + TextEditor::InputStyle::FONT_STYLE ), + TEST_LOCATION ); + + const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::YELLOW, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + END_TEST; +} + int utcDaliTextEditorEvent01(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp index cd3985a..3cc605c 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -105,8 +107,13 @@ const float TO_SECONDS = 1.f / TO_MILLISECONDS; const float SCROLL_THRESHOLD = 10.f; const float SCROLL_SPEED = 300.f; +const unsigned int DEFAULT_FONT_SIZE = 1152u; +const std::string DEFAULT_FONT_DIR( "/resources/fonts" ); + static bool gTextChangedCallBackCalled; static bool gMaxCharactersCallBackCalled; +static bool gInputStyleChangedCallbackCalled; +static Dali::Toolkit::TextField::InputStyle::Mask gInputStyleMask; static void LoadBitmapResource(TestPlatformAbstraction& platform, int width, int height) { @@ -206,6 +213,19 @@ static int Wait(ToolkitTestApplication& application, int duration = 0) return time; } +struct CallbackFunctor +{ + CallbackFunctor(bool* callbackFlag) + : mCallbackFlag( callbackFlag ) + { + } + + void operator()() + { + *mCallbackFlag = true; + } + bool* mCallbackFlag; +}; static void TestTextChangedCallback( TextField control ) { @@ -221,6 +241,14 @@ static void TestMaxLengthReachedCallback( TextField control ) gMaxCharactersCallBackCalled = true; } +static void TestInputStyleChangedCallback( TextField control, TextField::InputStyle::Mask mask ) +{ + tet_infoline(" TestInputStyleChangedCallback"); + + gInputStyleChangedCallbackCalled = true; + gInputStyleMask = mask; +} + // Generate a TapGestureEvent to send to Core. Integration::TapGestureEvent GenerateTap( Gesture::State state, @@ -641,11 +669,16 @@ int utcDaliTextFieldTextChangedP(void) Stage::GetCurrent().Add( field ); + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); field.TextChangedSignal().Connect(&TestTextChangedCallback); + bool textChangedSignal = false; + field.ConnectSignal( testTracker, "textChanged", CallbackFunctor(&textChangedSignal) ); gTextChangedCallBackCalled = false; field.SetProperty( TextField::Property::TEXT, "ABC" ); DALI_TEST_CHECK( gTextChangedCallBackCalled ); + DALI_TEST_CHECK( textChangedSignal ); application.SendNotification(); @@ -668,11 +701,16 @@ int utcDaliTextFieldTextChangedN(void) Stage::GetCurrent().Add( field ); + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); field.TextChangedSignal().Connect(&TestTextChangedCallback); + bool textChangedSignal = false; + field.ConnectSignal( testTracker, "textChanged", CallbackFunctor(&textChangedSignal) ); gTextChangedCallBackCalled = false; field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT DALI_TEST_CHECK( !gTextChangedCallBackCalled ); + DALI_TEST_CHECK( !textChangedSignal ); END_TEST; } @@ -692,13 +730,19 @@ int utcDaliTextFieldMaxCharactersReachedP(void) field.SetKeyInputFocus(); - gMaxCharactersCallBackCalled = false; + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback); + bool maxLengthReachedSignal = false; + field.ConnectSignal( testTracker, "maxLengthReached", CallbackFunctor(&maxLengthReachedSignal) ); + + gMaxCharactersCallBackCalled = false; application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); DALI_TEST_CHECK( gMaxCharactersCallBackCalled ); + DALI_TEST_CHECK( maxLengthReachedSignal ); END_TEST; } @@ -718,13 +762,441 @@ int utcDaliTextFieldMaxCharactersReachedN(void) field.SetKeyInputFocus(); - gMaxCharactersCallBackCalled = false; + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback); + bool maxLengthReachedSignal = false; + field.ConnectSignal( testTracker, "maxLengthReached", CallbackFunctor(&maxLengthReachedSignal) ); + + gMaxCharactersCallBackCalled = false; application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); DALI_TEST_CHECK( !gMaxCharactersCallBackCalled ); + DALI_TEST_CHECK( !maxLengthReachedSignal ); + + END_TEST; +} + +int utcDaliTextFieldInputStyleChanged01(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextFieldInputStyleChanged01"); + + // The text-field emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation. + // This creates an implementation of the adaptor stub and a queue of idle callbacks. + application.CreateAdaptor(); + + // Load some fonts. + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.SetDpi( 93u, 93u ); + + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE ); + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE ); + + TextField field = TextField::New(); + DALI_TEST_CHECK( field ); + + + field.SetSize( 300.f, 50.f ); + field.SetParentOrigin( ParentOrigin::TOP_LEFT ); + field.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + field.SetProperty( TextField::Property::ENABLE_MARKUP, true ); + field.SetProperty( TextField::Property::TEXT, "Hello world demo" ); + + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + field.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback ); + bool inputStyleChangedSignal = false; + field.ConnectSignal( testTracker, "inputStyleChanged", CallbackFunctor(&inputStyleChangedSignal) ); + + Stage::GetCurrent().Add( field ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 18.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 18.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextField::InputStyle::FONT_FAMILY | TextField::InputStyle::POINT_SIZE ), TEST_LOCATION ); + + const std::string fontFamily = field.GetProperty( TextField::Property::INPUT_FONT_FAMILY ).Get(); + DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION ); + + const float pointSize = field.GetProperty( TextField::Property::INPUT_POINT_SIZE ).Get(); + DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 30.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 43.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 43.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextField::InputStyle::COLOR ), TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 88.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 88.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextField::InputStyle::COLOR | TextField::InputStyle::FONT_STYLE ), TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + + const std::string style = field.GetProperty( TextField::Property::INPUT_FONT_STYLE ).Get(); + DALI_TEST_EQUALS( style, "{\"weight\":\"bold\"}", TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 115.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 115.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 164.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 164.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), static_cast( TextField::InputStyle::FONT_STYLE ), TEST_LOCATION ); + + const std::string style = field.GetProperty( TextField::Property::INPUT_FONT_STYLE ).Get(); + DALI_TEST_CHECK( style.empty() ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 191.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 191.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + END_TEST; +} + +int utcDaliTextFieldInputStyleChanged02(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextFieldInputStyleChanged02"); + + // The text-field emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation. + // This creates an implementation of the adaptor stub and a queue of idle callbacks. + application.CreateAdaptor(); + + // Load some fonts. + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.SetDpi( 93u, 93u ); + + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE ); + fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE ); + + TextField field = TextField::New(); + DALI_TEST_CHECK( field ); + + + field.SetSize( 300.f, 50.f ); + field.SetParentOrigin( ParentOrigin::TOP_LEFT ); + field.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + field.SetProperty( TextField::Property::ENABLE_MARKUP, true ); + field.SetProperty( TextField::Property::TEXT, "He llo world demo" ); + + // connect to the text changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + field.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback ); + bool inputStyleChangedSignal = false; + field.ConnectSignal( testTracker, "inputStyleChanged", CallbackFunctor(&inputStyleChangedSignal) ); + + Stage::GetCurrent().Add( field ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 53.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 53.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextField::InputStyle::FONT_FAMILY | + TextField::InputStyle::POINT_SIZE | + TextField::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION ); + + const std::string fontFamily = field.GetProperty( TextField::Property::INPUT_FONT_FAMILY ).Get(); + DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION ); + + const float pointSize = field.GetProperty( TextField::Property::INPUT_POINT_SIZE ).Get(); + DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextField::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLUE, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextField::InputStyle::COLOR ), + TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); + + gInputStyleChangedCallbackCalled = false; + gInputStyleMask = TextField::InputStyle::NONE; + inputStyleChangedSignal = false; + + field.SetProperty( TextField::Property::INPUT_COLOR, Color::YELLOW ); + + field.SetProperty( TextField::Property::INPUT_FONT_STYLE, "{\"weight\":\"thin\",\"width\":\"condensed\",\"slant\":\"italic\"}" ); + field.SetProperty( TextField::Property::INPUT_POINT_SIZE, 20.f ); + + field.SetProperty( TextField::Property::INPUT_UNDERLINE, "underline" ); + field.SetProperty( TextField::Property::INPUT_SHADOW, "shadow" ); + field.SetProperty( TextField::Property::INPUT_EMBOSS, "emboss" ); + field.SetProperty( TextField::Property::INPUT_OUTLINE, "outline" ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled ); + DALI_TEST_CHECK( !inputStyleChangedSignal ); + + // Create a tap event to touch the text field. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 63.f, 25.f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 63.f, 25.f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Executes the idle callbacks added by the text control on the change of input style. + application.RunIdles(); + + DALI_TEST_CHECK( gInputStyleChangedCallbackCalled ); + if( gInputStyleChangedCallbackCalled ) + { + DALI_TEST_EQUALS( static_cast( gInputStyleMask ), + static_cast( TextField::InputStyle::COLOR | + TextField::InputStyle::POINT_SIZE | + TextField::InputStyle::FONT_STYLE | + TextField::InputStyle::UNDERLINE | + TextField::InputStyle::SHADOW | + TextField::InputStyle::EMBOSS | + TextField::InputStyle::OUTLINE ), + TEST_LOCATION ); + + const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get(); + DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION ); + } + DALI_TEST_CHECK( inputStyleChangedSignal ); END_TEST; } 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 9bbce3b..2f333d4 100644 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -121,6 +122,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "outline", DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputOutline", STRING, INPUT_OUTLINE ) DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED ) +DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED ) DALI_TYPE_REGISTRATION_END() @@ -904,6 +906,10 @@ bool TextEditor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface { editor.TextChangedSignal().Connect( tracker, functor ); } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_INPUT_STYLE_CHANGED ) ) + { + editor.InputStyleChangedSignal().Connect( tracker, functor ); + } else { // signalName does not match any signal @@ -918,6 +924,11 @@ Toolkit::TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal() return mTextChangedSignal; } +Toolkit::TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedSignal() +{ + return mInputStyleChangedSignal; +} + void TextEditor::OnInitialize() { Actor self = Self(); @@ -1034,6 +1045,25 @@ void TextEditor::OnRelayout( const Vector2& size, RelayoutContainer& container ) EnableClipping( true, size ); RenderText( updateTextType ); } + + // The text-editor emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation. + if( !mController->IsInputStyleChangedSignalsQueueEmpty() ) + { + if( Adaptor::IsAvailable() ) + { + Adaptor& adaptor = Adaptor::Get(); + + if( NULL == mIdleCallback ) + { + // @note: The callback manager takes the ownership of the callback object. + mIdleCallback = MakeCallback( this, &TextEditor::OnIdleSignal ); + adaptor.AddIdle( mIdleCallback ); + } + } + } } void TextEditor::RenderText( Text::Controller::UpdateTextType updateTextType ) @@ -1231,6 +1261,60 @@ void TextEditor::TextChanged() mTextChangedSignal.Emit( handle ); } +void TextEditor::InputStyleChanged( Text::InputStyle::Mask inputStyleMask ) +{ + Dali::Toolkit::TextEditor handle( GetOwner() ); + + Toolkit::TextEditor::InputStyle::Mask editorInputStyleMask = Toolkit::TextEditor::InputStyle::NONE; + + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_COLOR ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::COLOR ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_FAMILY ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_FAMILY ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_POINT_SIZE ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::POINT_SIZE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_WEIGHT ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_WIDTH ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_SLANT ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_LINE_SPACING ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::LINE_SPACING ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_UNDERLINE ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::UNDERLINE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_SHADOW ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::SHADOW ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_EMBOSS ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::EMBOSS ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_OUTLINE ) ) + { + editorInputStyleMask = static_cast( editorInputStyleMask | Toolkit::TextEditor::InputStyle::OUTLINE ); + } + + mInputStyleChangedSignal.Emit( handle, editorInputStyleMask ); +} + void TextEditor::MaxLengthReached() { // Nothing to do as TextEditor doesn't emit a max length reached signal. @@ -1333,8 +1417,18 @@ bool TextEditor::OnTouched( Actor actor, const TouchData& touch ) return true; } +void TextEditor::OnIdleSignal() +{ + // Emits the change of input style signals. + mController->ProcessInputStyleChangedSignals(); + + // Set the pointer to null as the callback manager deletes the callback after execute it. + mIdleCallback = NULL; +} + TextEditor::TextEditor() : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ), + mIdleCallback( NULL ), mRenderingBackend( DEFAULT_RENDERING_BACKEND ), mHasBeenStaged( false ) { @@ -1343,6 +1437,12 @@ TextEditor::TextEditor() TextEditor::~TextEditor() { mClipper.Reset(); + + if( ( NULL != mIdleCallback ) && Adaptor::IsAvailable() ) + { + // Removes the callback from the callback manager in case the text-editor is destroyed before the callback is executed. + Adaptor::Get().RemoveIdle( mIdleCallback ); + } } } // namespace Internal 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 1c7376d..cb40406 100644 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h @@ -87,6 +87,11 @@ public: */ Toolkit::TextEditor::TextChangedSignalType& TextChangedSignal(); + /** + * @copydoc TextEditor::TextChangedSignal() + */ + Toolkit::TextEditor::InputStyleChangedSignalType& InputStyleChangedSignal(); + private: // From Control /** @@ -171,6 +176,11 @@ private: // From Control */ virtual void MaxLengthReached(); + /** + * @copydoc Text::ControlInterface::InputStyleChanged() + */ + virtual void InputStyleChanged( Text::InputStyle::Mask inputStyleMask ); + private: // Implementation /** @@ -216,6 +226,13 @@ private: // Implementation bool OnTouched( Actor actor, const TouchData& touch ); /** + * @brief Callbacks called on idle. + * + * If there are notifications of change of input style on the queue, Toolkit::TextEditor::InputStyleChangedSignal() are emitted. + */ + void OnIdleSignal(); + + /** * Construct a new TextEditor. */ TextEditor(); @@ -241,6 +258,7 @@ private: // Data // Signals Toolkit::TextEditor::TextChangedSignalType mTextChangedSignal; + Toolkit::TextEditor::InputStyleChangedSignalType mInputStyleChangedSignal; Text::ControllerPtr mController; Text::RendererPtr mRenderer; @@ -249,6 +267,7 @@ private: // Data std::vector mClippingDecorationActors; ///< Decoration actors which need clipping. Actor mRenderableActor; + CallbackBase* mIdleCallback; int mRenderingBackend; bool mHasBeenStaged:1; 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 4436731..13b0323 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -25,6 +25,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -135,6 +136,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputOutline", DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "textChanged", SIGNAL_TEXT_CHANGED ) DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED ) +DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED ) DALI_TYPE_REGISTRATION_END() @@ -1080,6 +1082,10 @@ bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* { field.MaxLengthReachedSignal().Connect( tracker, functor ); } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_INPUT_STYLE_CHANGED ) ) + { + field.InputStyleChangedSignal().Connect( tracker, functor ); + } else { // signalName does not match any signal @@ -1099,6 +1105,11 @@ Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSigna return mMaxLengthReachedSignal; } +Toolkit::TextField::InputStyleChangedSignalType& TextField::InputStyleChangedSignal() +{ + return mInputStyleChangedSignal; +} + void TextField::OnInitialize() { Actor self = Self(); @@ -1214,9 +1225,28 @@ void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container ) EnableClipping( ( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy ), size ); RenderText( updateTextType ); } + + // The text-field emits signals when the input style changes. These changes of style are + // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals + // can't be emitted during the size negotiation as the callbacks may update the UI. + // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation. + if( !mController->IsInputStyleChangedSignalsQueueEmpty() ) + { + if( Adaptor::IsAvailable() ) + { + Adaptor& adaptor = Adaptor::Get(); + + if( NULL == mIdleCallback ) + { + // @note: The callback manager takes the ownership of the callback object. + mIdleCallback = MakeCallback( this, &TextField::OnIdleSignal ); + adaptor.AddIdle( mIdleCallback ); + } + } + } } -void TextField::RenderText( Text::Controller::UpdateTextType updateTextType ) + void TextField::RenderText( Text::Controller::UpdateTextType updateTextType ) { Actor self = Self(); Actor renderableActor; @@ -1412,6 +1442,56 @@ void TextField::TextChanged() mTextChangedSignal.Emit( handle ); } +void TextField::InputStyleChanged( Text::InputStyle::Mask inputStyleMask ) +{ + Dali::Toolkit::TextField handle( GetOwner() ); + + Toolkit::TextField::InputStyle::Mask fieldInputStyleMask = Toolkit::TextField::InputStyle::NONE; + + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_COLOR ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::COLOR ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_FAMILY ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_FAMILY ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_POINT_SIZE ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::POINT_SIZE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_WEIGHT ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_WIDTH ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_FONT_SLANT ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_UNDERLINE ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::UNDERLINE ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_SHADOW ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::SHADOW ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_EMBOSS ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::EMBOSS ); + } + if( InputStyle::NONE != static_cast( inputStyleMask & InputStyle::INPUT_OUTLINE ) ) + { + fieldInputStyleMask = static_cast( fieldInputStyleMask | Toolkit::TextField::InputStyle::OUTLINE ); + } + + mInputStyleChangedSignal.Emit( handle, fieldInputStyleMask ); +} + void TextField::OnStageConnect( Dali::Actor actor ) { if ( mHasBeenStaged ) @@ -1515,8 +1595,18 @@ bool TextField::OnTouched( Actor actor, const TouchData& touch ) return true; } +void TextField::OnIdleSignal() +{ + // Emits the change of input style signals. + mController->ProcessInputStyleChangedSignals(); + + // Set the pointer to null as the callback manager deletes the callback after execute it. + mIdleCallback = NULL; +} + TextField::TextField() : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ), + mIdleCallback( NULL ), mRenderingBackend( DEFAULT_RENDERING_BACKEND ), mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP ), mHasBeenStaged( false ) @@ -1526,6 +1616,11 @@ TextField::TextField() TextField::~TextField() { mClipper.Reset(); + + if( ( NULL != mIdleCallback ) && Adaptor::IsAvailable() ) + { + Adaptor::Get().RemoveIdle( mIdleCallback ); + } } } // namespace Internal 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 c574bb8..558cced 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_INTERNAL_TEXT_FIELD_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -92,6 +92,11 @@ public: */ Toolkit::TextField::MaxLengthReachedSignalType& MaxLengthReachedSignal(); + /** + * @copydoc TextField::TextChangedSignal() + */ + Toolkit::TextField::InputStyleChangedSignalType& InputStyleChangedSignal(); + private: // From Control /** @@ -176,6 +181,11 @@ private: // From Control */ virtual void MaxLengthReached(); + /** + * @copydoc Text::ControlInterface::InputStyleChanged() + */ + virtual void InputStyleChanged( Text::InputStyle::Mask inputStyleMask ); + private: // Implementation /** @@ -221,6 +231,13 @@ private: // Implementation bool OnTouched( Actor actor, const TouchData& touch ); /** + * @brief Callbacks called on idle. + * + * If there are notifications of change of input style on the queue, Toolkit::TextField::InputStyleChangedSignal() are emitted. + */ + void OnIdleSignal(); + + /** * Construct a new TextField. */ TextField(); @@ -247,6 +264,7 @@ private: // Data // Signals Toolkit::TextField::TextChangedSignalType mTextChangedSignal; Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal; + Toolkit::TextField::InputStyleChangedSignalType mInputStyleChangedSignal; Text::ControllerPtr mController; Text::RendererPtr mRenderer; @@ -255,6 +273,7 @@ private: // Data std::vector mClippingDecorationActors; ///< Decoration actors which need clipping. Actor mRenderableActor; + CallbackBase* mIdleCallback; int mRenderingBackend; int mExceedPolicy; diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 19e674b..037a3ce 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -806,7 +806,7 @@ void TextLabel::OnStageConnection( int depth ) void TextLabel::TextChanged() { - // TextLabel does not provide a signal for this + // TextLabel does not provide a signal for this. } void TextLabel::MaxLengthReached() @@ -814,6 +814,11 @@ void TextLabel::MaxLengthReached() // Pure Virtual from TextController Interface, only needed when inputting text } +void TextLabel::InputStyleChanged( Text::InputStyle::Mask inputStyleMask ) +{ + // TextLabel does not provide a signal for this. +} + void TextLabel::ScrollingFinished() { // Pure Virtual from TextScroller Interface diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/dali-toolkit/internal/controls/text-controls/text-label-impl.h index c2dd485..298ba1a 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_INTERNAL_TEXT_LABEL_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -119,6 +119,11 @@ private: // From Control */ virtual void MaxLengthReached(); + /** + * @copydoc Text::ControlInterface::InputStyleChanged() + */ + virtual void InputStyleChanged( Text::InputStyle::Mask inputStyleMask ); + private: // from TextScroller /** diff --git a/dali-toolkit/internal/text/input-style.h b/dali-toolkit/internal/text/input-style.h index 63add2d..54d5e80 100644 --- a/dali-toolkit/internal/text/input-style.h +++ b/dali-toolkit/internal/text/input-style.h @@ -19,7 +19,7 @@ */ // EXTERNAL INCLUDES -#include +#include // INTERNAL INCLUDES #include @@ -38,6 +38,22 @@ namespace Text */ struct InputStyle { + enum Mask + { + NONE = 0x0000, + INPUT_COLOR = 0x0001, + INPUT_FONT_FAMILY = 0x0002, + INPUT_POINT_SIZE = 0x0004, + INPUT_FONT_WEIGHT = 0x0008, + INPUT_FONT_WIDTH = 0x0010, + INPUT_FONT_SLANT = 0x0020, + INPUT_LINE_SPACING = 0x0040, + INPUT_UNDERLINE = 0x0080, + INPUT_SHADOW = 0x0100, + INPUT_EMBOSS = 0x0200, + INPUT_OUTLINE = 0x0400 + }; + InputStyle() : textColor( Color::BLACK ), familyName(), @@ -51,17 +67,150 @@ struct InputStyle embossProperties(), outlineProperties(), isDefaultColor( true ), - familyDefined( false ), - weightDefined( false ), - widthDefined( false ), - slantDefined( false ), - sizeDefined( false ), - lineSpacingDefined( false ) - {} + isFamilyDefined( false ), + isWeightDefined( false ), + isWidthDefined( false ), + isSlantDefined( false ), + isSizeDefined( false ), + isLineSpacingDefined( false ), + isUnderlineDefined( false ), + isShadowDefined( false ), + isEmbossDefined( false ), + isOutlineDefined( false ) + {} ~InputStyle() {}; + /** + * @brief + * + * Does not copy the font-style, underline, shadow, emboss and outline property strings. + */ + void Copy( const InputStyle& inputStyle ) + { + isDefaultColor = inputStyle.isDefaultColor; + textColor = inputStyle.textColor; + + isFamilyDefined = inputStyle.isFamilyDefined; + familyName = inputStyle.familyName; + + isWeightDefined = inputStyle.isWeightDefined; + weight = inputStyle.weight; + + isWidthDefined = inputStyle.isWidthDefined; + width = inputStyle.width; + + isSlantDefined = inputStyle.isSlantDefined; + slant = inputStyle.slant; + + isSizeDefined = inputStyle.isSizeDefined; + size = inputStyle.size; + + isLineSpacingDefined = inputStyle.isLineSpacingDefined; + lineSpacing = inputStyle.lineSpacing; + + isUnderlineDefined = inputStyle.isUnderlineDefined; + underlineProperties = inputStyle.underlineProperties; + + isShadowDefined = inputStyle.isShadowDefined; + shadowProperties = inputStyle.shadowProperties; + + isEmbossDefined = inputStyle.isEmbossDefined; + embossProperties = inputStyle.embossProperties; + + isOutlineDefined = inputStyle.isOutlineDefined; + outlineProperties = inputStyle.outlineProperties; + } + + /** + * @brief + * + * Does not compare the font-style, underline, shadow, emboss and outline property strings. + */ + bool Equal( const InputStyle& inputStyle ) const + { + if( ( isDefaultColor != inputStyle.isDefaultColor ) || + ( isFamilyDefined != inputStyle.isFamilyDefined ) || + ( isWeightDefined != inputStyle.isWeightDefined ) || + ( isWidthDefined != inputStyle.isWidthDefined ) || + ( isSlantDefined != inputStyle.isSlantDefined ) || + ( isSizeDefined != inputStyle.isSizeDefined ) || + ( isLineSpacingDefined != inputStyle.isLineSpacingDefined ) || + ( isUnderlineDefined != inputStyle.isUnderlineDefined ) || + ( isShadowDefined != inputStyle.isShadowDefined ) || + ( isEmbossDefined != inputStyle.isEmbossDefined ) || + ( isOutlineDefined != inputStyle.isOutlineDefined ) || + ( textColor != inputStyle.textColor ) || + ( familyName != inputStyle.familyName ) || + ( weight != inputStyle.weight ) || + ( width != inputStyle.width ) || + ( slant != inputStyle.slant ) || + ( size != inputStyle.size ) || + ( lineSpacing != inputStyle.lineSpacing ) || + ( underlineProperties != inputStyle.underlineProperties ) || + ( shadowProperties != inputStyle.shadowProperties ) || + ( embossProperties != inputStyle.embossProperties ) || + ( outlineProperties != inputStyle.outlineProperties ) ) + { + return false; + } + + return true; + } + + Mask GetInputStyleChangeMask( const InputStyle& inputStyle ) const + { + Mask mask = NONE; + + if( textColor != inputStyle.textColor ) + { + mask = static_cast( mask | INPUT_COLOR ); + } + if( familyName != inputStyle.familyName ) + { + mask = static_cast( mask | INPUT_FONT_FAMILY ); + } + if( weight != inputStyle.weight ) + { + mask = static_cast( mask | INPUT_FONT_WEIGHT ); + } + if( width != inputStyle.width ) + { + mask = static_cast( mask | INPUT_FONT_WIDTH ); + } + if( slant != inputStyle.slant ) + { + mask = static_cast( mask | INPUT_FONT_SLANT ); + } + if( size != inputStyle.size ) + { + mask = static_cast( mask | INPUT_POINT_SIZE ); + } + if( lineSpacing != inputStyle.lineSpacing ) + { + mask = static_cast( mask | INPUT_LINE_SPACING ); + } + if( underlineProperties != inputStyle.underlineProperties ) + { + mask = static_cast( mask | INPUT_UNDERLINE ); + } + if( shadowProperties != inputStyle.shadowProperties ) + { + mask = static_cast( mask | INPUT_SHADOW ); + } + if( embossProperties != inputStyle.embossProperties ) + { + mask = static_cast( mask | INPUT_EMBOSS ); + } + if( outlineProperties != inputStyle.outlineProperties ) + { + mask = static_cast( mask | INPUT_OUTLINE ); + } + + return mask; + } + Vector4 textColor; ///< The text's color. std::string familyName; ///< The font's family name. FontWeight weight; ///< The font's weight. @@ -70,19 +219,24 @@ struct InputStyle float size; ///< The font's size. float lineSpacing; ///< The line's spacing. + std::string underlineProperties; ///< The underline properties string. std::string shadowProperties; ///< The shadow properties string. std::string embossProperties; ///< The emboss properties string. std::string outlineProperties; ///< The outline properties string. - bool isDefaultColor : 1; ///< Whether the text's color is the default. - bool familyDefined : 1; ///< Whether the font's family is defined. - bool weightDefined : 1; ///< Whether the font's weight is defined. - bool widthDefined : 1; ///< Whether the font's width is defined. - bool slantDefined : 1; ///< Whether the font's slant is defined. - bool sizeDefined : 1; ///< Whether the font's size is defined. - - bool lineSpacingDefined : 1; ///< Whether the line spacing is defined. + bool isDefaultColor : 1; ///< Whether the text's color is the default. + bool isFamilyDefined : 1; ///< Whether the font's family is defined. + bool isWeightDefined : 1; ///< Whether the font's weight is defined. + bool isWidthDefined : 1; ///< Whether the font's width is defined. + bool isSlantDefined : 1; ///< Whether the font's slant is defined. + bool isSizeDefined : 1; ///< Whether the font's size is defined. + + bool isLineSpacingDefined : 1; ///< Whether the line spacing is defined. + bool isUnderlineDefined : 1; ///< Whether the underline parameters are defined. + bool isShadowDefined : 1; ///< Whether the shadow parameters are defined. + bool isEmbossDefined : 1; ///< Whether the emboss parameters are defined. + bool isOutlineDefined : 1; ///< Whether the outline parameters are defined. }; } // namespace Text diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp index dcfb3e4..9b66925 100644 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -380,7 +380,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + nameIndex ); style.familyName = std::string( fontDescriptionRun.familyName, fontDescriptionRun.familyLength ); - style.familyDefined = true; + style.isFamilyDefined = true; } // Set the font's weight if it's overriden. @@ -389,7 +389,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex ); style.weight = fontDescriptionRun.weight; - style.weightDefined = true; + style.isWeightDefined = true; } // Set the font's width if it's overriden. @@ -398,7 +398,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex ); style.width = fontDescriptionRun.width; - style.widthDefined = true; + style.isWidthDefined = true; } // Set the font's slant if it's overriden. @@ -407,7 +407,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex ); style.slant = fontDescriptionRun.slant; - style.slantDefined = true; + style.isSlantDefined = true; } // Set the font's size if it's overriden. @@ -416,7 +416,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex ); style.size = static_cast( fontDescriptionRun.size ) / 64.f; - style.sizeDefined = true; + style.isSizeDefined = true; } } diff --git a/dali-toolkit/internal/text/text-control-interface.h b/dali-toolkit/internal/text/text-control-interface.h index ede1531..f5346e0 100644 --- a/dali-toolkit/internal/text/text-control-interface.h +++ b/dali-toolkit/internal/text/text-control-interface.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -18,6 +18,9 @@ * */ +// INTERNAL INCLUDES +#include + namespace Dali { @@ -68,6 +71,13 @@ public: * @brief Called when the number of characters to be inserted exceeds the maximum limit */ virtual void MaxLengthReached() = 0; + + /** + * @brief Called to signal that input style has been changed. + * + * @param[in] inputStyleMask Mask with the bits of the input style that has changed. + */ + virtual void InputStyleChanged( InputStyle::Mask inputStyleMask ) = 0; }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 849eb26..b6efd59 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -73,6 +73,7 @@ EventData::EventData( DecoratorPtr decorator ) mPlaceholderTextInactive(), mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), mEventQueue(), + mInputStyleChangedQueue(), mState( INACTIVE ), mPrimaryCursorPosition( 0u ), mLeftSelectionPosition( 0u ), @@ -262,6 +263,10 @@ bool Controller::Impl::ProcessInputEvents() if( mEventData->mUpdateInputStyle ) { + // Keep a copy of the current input style. + InputStyle currentInputStyle; + currentInputStyle.Copy( mEventData->mInputStyle ); + // Set the default style first. RetrieveDefaultInputStyle( mEventData->mInputStyle ); @@ -271,6 +276,16 @@ bool Controller::Impl::ProcessInputEvents() // Retrieve the style from the style runs stored in the logical model. mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle ); + // Compare if the input style has changed. + const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle ); + + if( hasInputStyleChanged ) + { + const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle ); + // Queue the input style changed signal. + mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask ); + } + mEventData->mUpdateInputStyle = false; } @@ -1006,11 +1021,25 @@ void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle ) inputStyle.slant = TextAbstraction::FontSlant::NORMAL; inputStyle.size = 0.f; - inputStyle.familyDefined = false; - inputStyle.weightDefined = false; - inputStyle.widthDefined = false; - inputStyle.slantDefined = false; - inputStyle.sizeDefined = false; + inputStyle.lineSpacing = 0.f; + + inputStyle.underlineProperties.clear(); + inputStyle.shadowProperties.clear(); + inputStyle.embossProperties.clear(); + inputStyle.outlineProperties.clear(); + + inputStyle.isFamilyDefined = false; + inputStyle.isWeightDefined = false; + inputStyle.isWidthDefined = false; + inputStyle.isSlantDefined = false; + inputStyle.isSizeDefined = false; + + inputStyle.isLineSpacingDefined = false; + + inputStyle.isUnderlineDefined = false; + inputStyle.isShadowDefined = false; + inputStyle.isEmbossDefined = false; + inputStyle.isOutlineDefined = false; // Sets the default font's family name, weight, width, slant and size. if( mFontDefaults ) @@ -1018,31 +1047,31 @@ void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle ) if( mFontDefaults->familyDefined ) { inputStyle.familyName = mFontDefaults->mFontDescription.family; - inputStyle.familyDefined = true; + inputStyle.isFamilyDefined = true; } if( mFontDefaults->weightDefined ) { inputStyle.weight = mFontDefaults->mFontDescription.weight; - inputStyle.weightDefined = true; + inputStyle.isWeightDefined = true; } if( mFontDefaults->widthDefined ) { inputStyle.width = mFontDefaults->mFontDescription.width; - inputStyle.widthDefined = true; + inputStyle.isWidthDefined = true; } if( mFontDefaults->slantDefined ) { inputStyle.slant = mFontDefaults->mFontDescription.slant; - inputStyle.slantDefined = true; + inputStyle.isSlantDefined = true; } if( mFontDefaults->sizeDefined ) { inputStyle.size = mFontDefaults->mDefaultPointSize; - inputStyle.sizeDefined = true; + inputStyle.isSizeDefined = true; } } } @@ -1642,9 +1671,23 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete if( deleteAfterRetrieval ) // Only delete text if copied successfully { + // Keep a copy of the current input style. + InputStyle currentInputStyle; + currentInputStyle.Copy( mEventData->mInputStyle ); + // Set as input style the style of the first deleted character. mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle ); + // Compare if the input style has changed. + const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle ); + + if( hasInputStyleChanged ) + { + const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle ); + // Queue the input style changed signal. + mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask ); + } + mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast( lengthOfSelectedText ) ); // Mark the paragraphs to be updated. diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index f47fd54..af3c7c6 100644 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -116,6 +116,8 @@ struct EventData */ std::vector mEventQueue; ///< The queue of touch events etc. + Vector mInputStyleChangedQueue; ///< Queue of changes in the input style. Used to emit the signal in the iddle callback. + InputStyle mInputStyle; ///< The style to be set to the new inputed text. State mPreviousState; ///< Stores the current state before it's updated with the new one. diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 0b0b77d..07eb23b 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -640,11 +640,25 @@ bool Controller::RemoveText( int cursorOffset, if( UPDATE_INPUT_STYLE == type ) { + // Keep a copy of the current input style. + InputStyle currentInputStyle; + currentInputStyle.Copy( mImpl->mEventData->mInputStyle ); + // Set first the default input style. mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle ); // Update the input style. mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle ); + + // Compare if the input style has changed. + const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle ); + + if( hasInputStyleChanged ) + { + const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle ); + // Queue the input style changed signal. + mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask ); + } } // Updates the text style runs by removing characters. Runs with no characters are removed. @@ -896,7 +910,7 @@ void Controller::SetInputFontFamily( const std::string& fontFamily ) if( NULL != mImpl->mEventData ) { mImpl->mEventData->mInputStyle.familyName = fontFamily; - mImpl->mEventData->mInputStyle.familyDefined = true; + mImpl->mEventData->mInputStyle.isFamilyDefined = true; if( EventData::SELECTING == mImpl->mEventData->mState ) { @@ -955,7 +969,7 @@ void Controller::SetInputFontWeight( FontWeight weight ) if( NULL != mImpl->mEventData ) { mImpl->mEventData->mInputStyle.weight = weight; - mImpl->mEventData->mInputStyle.weightDefined = true; + mImpl->mEventData->mInputStyle.isWeightDefined = true; if( EventData::SELECTING == mImpl->mEventData->mState ) { @@ -1000,7 +1014,7 @@ bool Controller::IsInputFontWeightDefined() const if( NULL != mImpl->mEventData ) { - defined = mImpl->mEventData->mInputStyle.weightDefined; + defined = mImpl->mEventData->mInputStyle.isWeightDefined; } return defined; @@ -1021,7 +1035,7 @@ void Controller::SetInputFontWidth( FontWidth width ) if( NULL != mImpl->mEventData ) { mImpl->mEventData->mInputStyle.width = width; - mImpl->mEventData->mInputStyle.widthDefined = true; + mImpl->mEventData->mInputStyle.isWidthDefined = true; if( EventData::SELECTING == mImpl->mEventData->mState ) { @@ -1066,7 +1080,7 @@ bool Controller::IsInputFontWidthDefined() const if( NULL != mImpl->mEventData ) { - defined = mImpl->mEventData->mInputStyle.widthDefined; + defined = mImpl->mEventData->mInputStyle.isWidthDefined; } return defined; @@ -1087,7 +1101,7 @@ void Controller::SetInputFontSlant( FontSlant slant ) if( NULL != mImpl->mEventData ) { mImpl->mEventData->mInputStyle.slant = slant; - mImpl->mEventData->mInputStyle.slantDefined = true; + mImpl->mEventData->mInputStyle.isSlantDefined = true; if( EventData::SELECTING == mImpl->mEventData->mState ) { @@ -1132,7 +1146,7 @@ bool Controller::IsInputFontSlantDefined() const if( NULL != mImpl->mEventData ) { - defined = mImpl->mEventData->mInputStyle.slantDefined; + defined = mImpl->mEventData->mInputStyle.isSlantDefined; } return defined; @@ -1153,6 +1167,7 @@ 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 ) { @@ -1207,6 +1222,7 @@ void Controller::SetInputLineSpacing( float lineSpacing ) if( NULL != mImpl->mEventData ) { mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing; + mImpl->mEventData->mInputStyle.isLineSpacingDefined = true; } } @@ -1616,6 +1632,33 @@ void Controller::ProcessModifyEvents() events.Clear(); } +bool Controller::IsInputStyleChangedSignalsQueueEmpty() +{ + return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() ); +} + +void Controller::ProcessInputStyleChangedSignals() +{ + if( NULL == mImpl->mEventData ) + { + // Nothing to do. + return; + } + + for( Vector::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(), + endIt = mImpl->mEventData->mInputStyleChangedQueue.End(); + it != endIt; + ++it ) + { + const InputStyle::Mask mask = *it; + + // Emit the input style changed signal. + mImpl->mControlInterface.InputStyleChanged( mask ); + } + + mImpl->mEventData->mInputStyleChangedQueue.Clear(); +} + void Controller::ResetText() { // Reset buffers. @@ -2761,9 +2804,6 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons { mImpl->mOperationsPending = ALL_OPERATIONS; mImpl->RequestRelayout(); - - // Do this last since it provides callbacks into application code - mImpl->mControlInterface.TextChanged(); } std::string text; @@ -2793,6 +2833,12 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); + if( requestRelayout ) + { + // Do this last since it provides callbacks into application code + mImpl->mControlInterface.TextChanged(); + } + return callbackData; } diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 7b1e2ba..ebad670 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -782,6 +782,19 @@ public: void ProcessModifyEvents(); /** + * @return Whether the queue of input style changed signals is empty. + */ + bool IsInputStyleChangedSignalsQueueEmpty(); + + /** + * @brief Process all pending input style changed signals. + * + * Calls the Text::ControlInterface::InputStyleChanged() method which is overriden by the + * text controls. Text controls may send signals to state the input style has changed. + */ + void ProcessInputStyleChangedSignals(); + + /** * @brief Used to remove placeholder text. */ void ResetText(); diff --git a/dali-toolkit/public-api/controls/text-controls/text-editor.cpp b/dali-toolkit/public-api/controls/text-controls/text-editor.cpp index fa81f24..4098e8b 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-editor.cpp +++ b/dali-toolkit/public-api/controls/text-controls/text-editor.cpp @@ -64,6 +64,11 @@ TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal() return Dali::Toolkit::GetImpl( *this ).TextChangedSignal(); } +TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedSignal() +{ + return Dali::Toolkit::GetImpl( *this ).InputStyleChangedSignal(); +} + TextEditor::TextEditor( Internal::TextEditor& implementation ) : Control( implementation ) { diff --git a/dali-toolkit/public-api/controls/text-controls/text-editor.h b/dali-toolkit/public-api/controls/text-controls/text-editor.h index fc7b701..e6e05f8 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-editor.h +++ b/dali-toolkit/public-api/controls/text-controls/text-editor.h @@ -40,9 +40,10 @@ class TextEditor; * @brief A control which provides a multi-line editable text editor. * * * Signals - * | %Signal Name | Method | - * |----------------------|-----------------------------------------------------| - * | textChanged | @ref TextChangedSignal() | + * | %Signal Name | Method | | + * |----------------------|--------------------------------|--------------------| + * | textChanged | @ref TextChangedSignal() | @SINCE_1_1.37 | + * | inputStyleChanged | @ref InputStyleChangedSignal() | @SINCE_1_2.2 | * */ class DALI_IMPORT_API TextEditor : public Control @@ -51,6 +52,7 @@ public: /** * @brief The start and end property ranges for this control. + * @SINCE_1_1.37 */ enum PropertyRange { @@ -60,6 +62,7 @@ public: /** * @brief An enumeration of properties belonging to the TextEditor class. + * @SINCE_1_1.37 */ struct Property { @@ -108,25 +111,61 @@ public: }; }; + /** + * @brief Mask used by the signal InputStyleChangedSignal(). Notifies which parameters of the input style have changed. + * + * @SINCE_1_2.2 + */ + struct InputStyle + { + enum Mask + { + NONE = 0x0000, ///< @SINCE_1_2.2 + COLOR = 0x0001, ///< @SINCE_1_2.2 + FONT_FAMILY = 0x0002, ///< @SINCE_1_2.2 + POINT_SIZE = 0x0004, ///< @SINCE_1_2.2 + FONT_STYLE = 0x0008, ///< @SINCE_1_2.2 + LINE_SPACING = 0x0010, ///< @SINCE_1_2.2 + UNDERLINE = 0x0020, ///< @SINCE_1_2.2 + SHADOW = 0x0040, ///< @SINCE_1_2.2 + EMBOSS = 0x0080, ///< @SINCE_1_2.2 + OUTLINE = 0x0100 ///< @SINCE_1_2.2 + }; + }; + // Type Defs - /// @brief Text changed signal type. + /** + * @brief Text changed signal type. + * @SINCE_1_1.37 + */ typedef Signal TextChangedSignalType; /** + * @brief Input Style changed signal type. + * @SINCE_1_2.2 + */ + typedef Signal InputStyleChangedSignalType; + + /** * @brief Create the TextEditor control. + * + * @SINCE_1_1.37 * @return A handle to the TextEditor control. */ static TextEditor New(); /** * @brief Creates an empty handle. + * + * @SINCE_1_1.37 */ TextEditor(); /** * @brief Copy constructor. * + * @SINCE_1_1.37 * @param[in] handle The handle to copy from. */ TextEditor( const TextEditor& handle ); @@ -134,6 +173,7 @@ public: /** * @brief Assignment operator. * + * @SINCE_1_1.37 * @param[in] handle The handle to copy from. * @return A reference to this. */ @@ -143,6 +183,7 @@ public: * @brief Destructor. * * This is non-virtual since derived Handle types must not contain data or virtual methods. + * @SINCE_1_1.37 */ ~TextEditor(); @@ -152,6 +193,7 @@ public: * If the BaseHandle points is a TextEditor the downcast returns a valid handle. * If not the returned handle is left empty. * + * @SINCE_1_1.37 * @param[in] handle Handle to an object. * @return handle to a TextEditor or an empty handle. */ @@ -166,16 +208,33 @@ public: * @code * void YourCallbackName( TextEditor textEditor ); * @endcode + * + * @SINCE_1_1.37 * @return The signal to connect to. */ TextChangedSignalType& TextChangedSignal(); + /** + * @brief This signal is emitted when the input style is updated as a consequence of a change in the cursor position. + * i.e. The signal is not emitted when the input style is updated through the property system. + * + * A callback of the following type may be connected. The @p mask parameter notifies which parts of the style have changed. + * @code + * void YourCallbackName( TextEditor textEditor, TextEditor::InputStyle::Mask mask ); + * @endcode + * + * @SINCE_1_2.2 + * @return The signal to connect to. + */ + InputStyleChangedSignalType& InputStyleChangedSignal(); + public: // Not intended for application developers /// @cond internal /** * @brief Creates a handle using the Toolkit::Internal implementation. * + * @SINCE_1_1.37 * @param[in] implementation The Control implementation. */ DALI_INTERNAL TextEditor( Internal::TextEditor& implementation ); @@ -183,6 +242,7 @@ public: // Not intended for application developers /** * @brief Allows the creation of this Control from an Internal::CustomActor pointer. * + * @SINCE_1_1.37 * @param[in] internal A pointer to the internal CustomActor. */ explicit DALI_INTERNAL TextEditor( Dali::Internal::CustomActor* internal ); diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.cpp b/dali-toolkit/public-api/controls/text-controls/text-field.cpp index 3a833f3..fc58261 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-field.cpp +++ b/dali-toolkit/public-api/controls/text-controls/text-field.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -69,6 +69,11 @@ TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal() return Dali::Toolkit::GetImpl( *this ).MaxLengthReachedSignal(); } +TextField::InputStyleChangedSignalType& TextField::InputStyleChangedSignal() +{ + return Dali::Toolkit::GetImpl( *this ).InputStyleChangedSignal(); +} + TextField::TextField( Internal::TextField& implementation ) : Control(implementation) { diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.h b/dali-toolkit/public-api/controls/text-controls/text-field.h index fc29af4..f33483c 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-field.h +++ b/dali-toolkit/public-api/controls/text-controls/text-field.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_TEXT_FIELD_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -40,12 +40,11 @@ class TextField; * @brief A control which provides a single-line editable text field. * * * Signals - * | %Signal Name | Method | - * |----------------------|-----------------------------------------------------| - * | textChanged | @ref TextChangedSignal() | - * | maxLengthReached | @ref MaxLengthReachedSignal() | - * - * @SINCE_1_0.0 + * | %Signal Name | Method | | + * |----------------------|--------------------------------|--------------------| + * | textChanged | @ref TextChangedSignal() | @SINCE_1_0.0 | + * | maxLengthReached | @ref MaxLengthReachedSignal() | @SINCE_1_0.0 | + * | inputStyleChanged | @ref InputStyleChangedSignal() | @SINCE_1_2.2 | */ class DALI_IMPORT_API TextField : public Control { @@ -131,14 +130,48 @@ public: EXCEED_POLICY_CLIP ///< The end of text will be clipped to fit within the TextField. @SINCE_1_0.0 }; + /** + * @brief Mask used by the signal InputStyleChangedSignal(). Notifies which parameters of the input style have changed. + * + * @SINCE_1_2.2 + */ + struct InputStyle + { + enum Mask + { + NONE = 0x0000, ///< @SINCE_1_2.2 + COLOR = 0x0001, ///< @SINCE_1_2.2 + FONT_FAMILY = 0x0002, ///< @SINCE_1_2.2 + POINT_SIZE = 0x0004, ///< @SINCE_1_2.2 + FONT_STYLE = 0x0008, ///< @SINCE_1_2.2 + UNDERLINE = 0x0010, ///< @SINCE_1_2.2 + SHADOW = 0x0020, ///< @SINCE_1_2.2 + EMBOSS = 0x0040, ///< @SINCE_1_2.2 + OUTLINE = 0x0080 ///< @SINCE_1_2.2 + }; + }; + // Type Defs - /// @brief Text changed signal type. + /** + * @brief Text changed signal type. + * @SINCE_1_0.0 + */ typedef Signal TextChangedSignalType; - /// @brief Max Characters Exceed signal type. + + /** + * @brief Max Characters Exceed signal type. + * @SINCE_1_0.0 + */ typedef Signal MaxLengthReachedSignalType; /** + * @brief Input Style changed signal type. + * @SINCE_1_2.2 + */ + typedef Signal InputStyleChangedSignalType; + + /** * @brief Create the TextField control. * @SINCE_1_0.0 * @return A handle to the TextField control. @@ -214,6 +247,20 @@ public: */ MaxLengthReachedSignalType& MaxLengthReachedSignal(); + /** + * @brief This signal is emitted when the input style is updated as a consequence of a change in the cursor position. + * i.e. The signal is not emitted when the input style is updated through the property system. + * + * A callback of the following type may be connected. The @p mask parameter notifies which parts of the style have changed. + * @code + * void YourCallbackName( TextField textField, TextField::InputStyle::Mask mask ); + * @endcode + * + * @SINCE_1_2.2 + * @return The signal to connect to. + */ + InputStyleChangedSignalType& InputStyleChangedSignal(); + public: // Not intended for application developers /**