From: Adeel Kazmi Date: Thu, 23 Feb 2017 18:36:48 +0000 (-0800) Subject: Merge "Fixed the ItemView already scrolled to end logic" into devel/master X-Git-Tag: dali_1.2.28~3 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=cb30ef68af0383b073ba2d425d3d95c1e916cbb4;hp=519e8598015b2c57a7ab004510bc1dd53cc48cd5 Merge "Fixed the ItemView already scrolled to end logic" into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index f07653b..023d4bc 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -24,6 +24,7 @@ SET(TC_SOURCES utc-Dali-DebugRendering.cpp utc-Dali-ItemView-internal.cpp utc-Dali-PropertyHelper.cpp + utc-Dali-ColorConversion.cpp ) # Append list of test harness files (Won't get parsed for test cases) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp new file mode 100644 index 0000000..14cef1c --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +using namespace Dali; +using namespace Dali::Toolkit; + +void dali_color_conversion_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void dali_color_conversion_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int UtcDaliPropertyHelperConvertHtmlStringToColor(void) +{ + tet_infoline( "Test to check whether An HTML style hex string can be converted" ); + + const std::string stringColor( "#FF0000" ); + + Vector4 result; + DALI_TEST_CHECK( Toolkit::Internal::ConvertStringToColor( stringColor, result ) ); + + DALI_TEST_EQUALS( result, Color::RED, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliPropertyHelperConvertStringPropertyToColor(void) +{ + tet_infoline( "Test to check whether A Property value containing a string can be converted" ); + + const std::string stringColor( "#00FF00" ); + Property::Value colorProperty( stringColor ); + + Vector4 result; + DALI_TEST_CHECK( Toolkit::Internal::ConvertPropertyToColor( colorProperty, result ) ); + + DALI_TEST_EQUALS( result, Color::GREEN, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliPropertyHelperConvertVector4PropertyToColor(void) +{ + tet_infoline( "Test to check whether A Property value containing a string can be converted" ); + + const Vector4 color( 0.0, 0.0, 1.0, 1.0 ); + Property::Value colorProperty( color ); + + Vector4 result; + DALI_TEST_CHECK( Toolkit::Internal::ConvertPropertyToColor( colorProperty, result ) ); + + DALI_TEST_EQUALS( result, Color::BLUE, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-styling/theme2.json b/automated-tests/src/dali-toolkit-styling/theme2.json new file mode 100644 index 0000000..8ca44cd --- /dev/null +++ b/automated-tests/src/dali-toolkit-styling/theme2.json @@ -0,0 +1,9 @@ +{ + "styles": + { + "testbutton": + { + "backgroundColor":[1.0,1.0,0.0,1.0] + } + } +} diff --git a/automated-tests/src/dali-toolkit-styling/theme3.json b/automated-tests/src/dali-toolkit-styling/theme3.json new file mode 100644 index 0000000..68a292e --- /dev/null +++ b/automated-tests/src/dali-toolkit-styling/theme3.json @@ -0,0 +1,10 @@ +{ + "styles": + { + "testbutton": + { + "backgroundColor":[1.0,1.0,0.0,1.0] +// Deliberate Error: trailing comma + }, + }, +} diff --git a/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp b/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp index 8d93d9c..6fe0fde 100644 --- a/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp +++ b/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -33,6 +36,10 @@ namespace { const char* defaultTheme = "{\n" +" \"constants\":\n" +" {\n" +" \"CONFIG_SCRIPT_LOG_LEVEL\":\"NoLogging\"\n" +" },\n" " \"styles\":\n" " {\n" " \"textlabel\":\n" @@ -146,6 +153,223 @@ const char* defaultTheme = " \"grabHandleImage\" : \"{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png\",\n" " \"selectionHandleImageLeft\" : {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png\" },\n" " \"selectionHandleImageRight\": {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png\" }\n" +" },\n" +" \"ComplexControl\":\n" +" {\n" +" \"states\":\n" +" {\n" +" \"NORMAL\":\n" +" {\n" +" \"states\":\n" +" {\n" +" \"SELECTED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"GRADIENT\",\n" +" \"startPosition\": [-1, -1],\n" +" \"endPosition\": [1, 1],\n" +" \"spreadMethod\": \"REPEAT\",\n" +" \"stopOffset\": [0.2, 0.8],\n" +" \"stopColor\": [ [ 1,0,0,1], [0,1,0,1] ]\n" +" }\n" +" }\n" +" },\n" +" \"UNSELECTED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"COLOR\",\n" +" \"mixColor\": [ 1,0,0,1]\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"transitions\":\n" +" {\n" +" \"visualName\":\"*\",\n" +" \"effect\":\"CROSSFADE\",\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT\",\n" +" \"duration\":0.3\n" +" }\n" +" }\n" +" },\n" +" \"FOCUSED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"GRADIENT\",\n" +" \"startPosition\": [-1, -1],\n" +" \"endPosition\": [1, 1],\n" +" \"spreadMethod\": \"REPEAT\",\n" +" \"stopOffset\": [0.3, 0.9],\n" +" \"stopColor\": [ [ 0,0,1,1], [0,1,1,1] ]\n" +" },\n" +" \"focusVisual\":\n" +" {\n" +" \"visualType\":\"IMAGE\",\n" +" \"url\": \"focus.png\"\n" +" }\n" +" },\n" +" \"entryTransition\":\n" +" {\n" +" \"target\":\"focusVisual\",\n" +" \"property\":\"mixColor\",\n" +" \"initialValue\":[0,0,0,0],\n" +" \"targetValue\":[1,1,1,1],\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n" +" \"timePeriod\": \n" +" {\n" +" \"duration\":0.5,\n" +" \"delay\":0\n" +" }\n" +" }\n" +" },\n" +" \"exitTransition\":\n" +" {\n" +" \"target\":\"focusVisual\",\n" +" \"property\":\"mixColor\",\n" +" \"initialValue\":[1,1,1,1],\n" +" \"targetValue\":[0,0,0,0],\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n" +" \"timePeriod\": \n" +" {\n" +" \"duration\":0.5,\n" +" \"delay\":0\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"DISABLED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"COLOR\",\n" +" \"mixColor\": [1,0,0,1]\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"transitions\":\n" +" [\n" +" {\n" +" \"effect\":\"CROSSFADE\",\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT\",\n" +" \"duration\":0.3\n" +" }\n" +" }\n" +" ]\n" +" },\n" +" \"BasicControl\":\n" +" {\n" +" \"states\":\n" +" {\n" +" \"NORMAL\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"GRADIENT\",\n" +" \"startPosition\": [-1, -1],\n" +" \"endPosition\": [1, 1],\n" +" \"spreadMethod\": \"REPEAT\",\n" +" \"stopOffset\": [0.2, 0.8],\n" +" \"stopColor\": [ [ 1,0,0,1], [0,1,0,1] ]\n" +" }\n" +" }\n" +" },\n" +" \"FOCUSED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"GRADIENT\",\n" +" \"startPosition\": [-1, -1],\n" +" \"endPosition\": [1, 1],\n" +" \"spreadMethod\": \"REPEAT\",\n" +" \"stopOffset\": [0.3, 0.9],\n" +" \"stopColor\": [ [ 0,0,1,1], [0,1,1,1] ]\n" +" },\n" +" \"focusVisual\":\n" +" {\n" +" \"visualType\":\"IMAGE\",\n" +" \"url\": \"focus.png\"\n" +" }\n" +" },\n" +" \"entryTransition\":\n" +" {\n" +" \"target\":\"focusVisual\",\n" +" \"property\":\"mixColor\",\n" +" \"initialValue\":[0,0,0,0],\n" +" \"targetValue\":[1,1,1,1],\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n" +" \"timePeriod\": \n" +" {\n" +" \"duration\":0.5,\n" +" \"delay\":0\n" +" }\n" +" }\n" +" },\n" +" \"exitTransition\":\n" +" {\n" +" \"target\":\"focusVisual\",\n" +" \"property\":\"mixColor\",\n" +" \"initialValue\":[1,1,1,1],\n" +" \"targetValue\":[0,0,0,0],\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n" +" \"timePeriod\": \n" +" {\n" +" \"duration\":0.5,\n" +" \"delay\":0\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"DISABLED\":\n" +" {\n" +" \"visuals\":\n" +" {\n" +" \"foregroundVisual\":\n" +" {\n" +" \"visualType\":\"COLOR\",\n" +" \"mixColor\": [1,0,0,1]\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"transitions\":\n" +" [\n" +" {\n" +" \"effect\":\"CROSSFADE\",\n" +" \"animator\":\n" +" {\n" +" \"alphaFunction\":\"EASE_IN_OUT\",\n" +" \"duration\":0.3\n" +" }\n" +" }\n" +" ]\n" " }\n" " }\n" "}\n"; @@ -154,6 +378,7 @@ const char* defaultTheme = + void dali_style_manager_startup(void) { test_return_value = TET_UNDEF; @@ -258,6 +483,10 @@ int UtcDaliStyleManagerApplyTheme(void) const char* json1 = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"Verbose\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -362,6 +591,10 @@ int UtcDaliStyleManagerApplyDefaultTheme(void) const char* defaultTheme = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"Concise\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -505,6 +738,10 @@ int UtcDaliStyleManagerApplyStyle(void) const char* json1 = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"General\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -574,6 +811,107 @@ int UtcDaliStyleManagerApplyStyle(void) } +int UtcDaliStyleManagerIncludeStyleP(void) +{ + ToolkitTestApplication application; + + tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works" ); + + const char* json1 = + "{\n" + " \"includes\":\n" + " [\n" + " \"src/dali-toolkit-styling/theme2.json\"\n" + " ],\n" + " \"styles\":\n" + " {\n" + " \"testbutton\":\n" + " {\n" + " \"foregroundColor\":[0.0,0.0,1.0,1.0]\n" + " }\n" + " }\n" + "}\n"; + + // Add 2 buttons + Test::TestButton testButton = Test::TestButton::New(); + Test::TestButton testButton2 = Test::TestButton::New(); + Stage::GetCurrent().Add( testButton ); + Stage::GetCurrent().Add( testButton2 ); + StyleChangedSignalChecker styleChangedSignalHandler; + StyleManager styleManager = StyleManager::Get(); + + styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged); + + tet_infoline("Apply the style"); + + std::string themeFile("ThemeOne"); + Test::StyleMonitor::SetThemeFileOutput(themeFile, json1); + + styleManager.ApplyTheme(themeFile); + + // Render and notify + application.SendNotification(); + application.Render(); + + Property::Value themedBgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) ); + Property::Value themedFgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) ); + + DALI_TEST_EQUALS( themedBgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION ); + DALI_TEST_EQUALS( themedFgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliStyleManagerIncludeStyleN(void) +{ + ToolkitTestApplication application; + + tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works, but included stylesheet is bad json" ); + + const char* json1 = + "{\n" + " \"includes\":\n" + " [\n" + " \"src/dali-toolkit-styling/theme3.json\"\n" + " ],\n" + " \"styles\":\n" + " {\n" + " \"testbutton\":\n" + " {\n" + " \"foregroundColor\":[0.0,0.0,1.0,1.0]\n" + " }\n" + " }\n" + "}\n"; + + // Add 2 buttons + Test::TestButton testButton = Test::TestButton::New(); + Test::TestButton testButton2 = Test::TestButton::New(); + Stage::GetCurrent().Add( testButton ); + Stage::GetCurrent().Add( testButton2 ); + StyleChangedSignalChecker styleChangedSignalHandler; + StyleManager styleManager = StyleManager::Get(); + + styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged); + + tet_infoline("Apply the style"); + + std::string themeFile("ThemeOne"); + Test::StyleMonitor::SetThemeFileOutput(themeFile, json1); + + try + { + styleManager.ApplyTheme(themeFile); + } + catch( Dali::DaliException& e ) + { + DALI_TEST_ASSERT( e, "!\"Cannot parse JSON\"", TEST_LOCATION ); + } + + END_TEST; +} + + int UtcDaliStyleManagerStyleChangedSignalFontFamily(void) { tet_infoline("Test that the StyleChange signal is fired when the font family is altered" ); @@ -860,3 +1198,85 @@ int UtcDaliStyleManagerStyleChangedSignalFontSizeTextEditor(void) END_TEST; } + + +int UtcDaliStyleManagerVisualTransitionParsing(void) +{ + tet_infoline("Instantiate dummy control and test state/visual/transition capture" ); + Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json", + defaultTheme ); + + ToolkitTestApplication application; + + StyleChangedSignalChecker styleChangedSignalHandler; + Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get(); + StyleManager styleManager = StyleManager::Get(); + + DummyControl actor = DummyControl::New(true); + actor.SetStyleName("BasicControl"); + Stage::GetCurrent().Add(actor); + + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION); + Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL); + + actor.SetProperty( DevelControl::Property::STATE, DevelControl::FOCUSED ); + + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION); + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), true, TEST_LOCATION); + + Visual::Base visual2 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL); + DALI_TEST_CHECK( visual1 != visual2 ); + + actor.SetProperty( DevelControl::Property::STATE, DevelControl::DISABLED ); + + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION); + + Visual::Base visual3 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL); + Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL); + DALI_TEST_CHECK( !focusVisual ); + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), false, TEST_LOCATION); + + DALI_TEST_CHECK( visual1 != visual3 ); + DALI_TEST_CHECK( visual2 != visual3 ); + + END_TEST; +} + + +int UtcDaliStyleManagerVisualTransitionParsing02(void) +{ + tet_infoline("Instantiate dummy control and test state/visual/transition capture" ); + Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json", + defaultTheme ); + + ToolkitTestApplication application; + + StyleChangedSignalChecker styleChangedSignalHandler; + Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get(); + StyleManager styleManager = StyleManager::Get(); + + DummyControl actor = DummyControl::New(true); + actor.SetProperty(DevelControl::Property::STATE, "FOCUSED"); + + actor.SetStyleName("ComplexControl"); + Stage::GetCurrent().Add(actor); + + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + + DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION); + Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL); + DALI_TEST_CHECK( visual1 ); + Property::Map map; + visual1.CreatePropertyMap( map ); + Property::Value* value = map.Find( Visual::Property::TYPE ); + DALI_TEST_CHECK( value ); + + int visualType; + value->Get( visualType ); + + DALI_TEST_EQUALS( visualType, (int)Toolkit::Visual::GRADIENT, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h index 79d422b..03c788c 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h @@ -20,10 +20,13 @@ // EXTERNAL INCLUDES #include +#include #include +#include // INTERNAL INCLUDES #include +#include void tet_infoline(const char*str); void tet_printf(const char *format, ...); @@ -73,176 +76,6 @@ else throw("TET_FAIL"); \ } -template -inline bool CompareType(Type value1, Type value2, float epsilon); - -/** - * A helper for fuzzy-comparing Vector2 objects - * @param[in] vector1 the first object - * @param[in] vector2 the second object - * @param[in] epsilon difference threshold - * @returns true if difference is smaller than epsilon threshold, false otherwise - */ -template <> -inline bool CompareType(float value1, float value2, float epsilon) -{ - return fabsf(value1 - value2) < epsilon; -} - -/** - * A helper for fuzzy-comparing Vector2 objects - * @param[in] vector1 the first object - * @param[in] vector2 the second object - * @param[in] epsilon difference threshold - * @returns true if difference is smaller than epsilon threshold, false otherwise - */ -template <> -inline bool CompareType(Vector2 vector1, Vector2 vector2, float epsilon) -{ - return fabsf(vector1.x - vector2.x) -inline bool CompareType(Vector3 vector1, Vector3 vector2, float epsilon) -{ - return fabsf(vector1.x - vector2.x) -inline bool CompareType(Vector4 vector1, Vector4 vector2, float epsilon) -{ - return fabsf(vector1.x - vector2.x) -inline bool CompareType(Quaternion q1, Quaternion q2, float epsilon) -{ - Quaternion q2N = -q2; // These quaternions represent the same rotation - return CompareType(q1.mVector, q2.mVector, epsilon) || CompareType(q1.mVector, q2N.mVector, epsilon); -} - -template <> -inline bool CompareType(Radian q1, Radian q2, float epsilon) -{ - return CompareType(q1.radian, q2.radian, epsilon); -} - -template <> -inline bool CompareType(Degree q1, Degree q2, float epsilon) -{ - return CompareType(q1.degree, q2.degree, epsilon); -} - -template <> -inline bool CompareType(Property::Value q1, Property::Value q2, float epsilon) -{ - Property::Type type = q1.GetType(); - if( type != q2.GetType() ) - { - return false; - } - - bool result = false; - switch(type) - { - case Property::BOOLEAN: - { - bool a, b; - q1.Get(a); - q2.Get(b); - result = a == b; - break; - } - case Property::INTEGER: - { - int a, b; - q1.Get(a); - q2.Get(b); - result = a == b; - break; - } - case Property::FLOAT: - { - float a, b; - q1.Get(a); - q2.Get(b); - result = CompareType(a, b, epsilon); - break; - } - case Property::VECTOR2: - { - Vector2 a, b; - q1.Get(a); - q2.Get(b); - result = CompareType(a, b, epsilon); - break; - } - case Property::VECTOR3: - { - Vector3 a, b; - q1.Get(a); - q2.Get(b); - result = CompareType(a, b, epsilon); - break; - } - case Property::RECTANGLE: - case Property::VECTOR4: - { - Vector4 a, b; - q1.Get(a); - q2.Get(b); - result = CompareType(a, b, epsilon); - break; - } - case Property::ROTATION: - { - Quaternion a, b; - q1.Get(a); - q2.Get(b); - result = CompareType(a, b, epsilon); - break; - } - case Property::MATRIX: - case Property::MATRIX3: - case Property::STRING: - case Property::ARRAY: - case Property::MAP: - { - //TODO: Implement this? - DALI_ASSERT_ALWAYS( 0 && "Not implemented"); - result = false; - break; - } - case Property::NONE: - { - result = false; - break; - } - } - - return result; -} - bool operator==(TimePeriod a, TimePeriod b); std::ostream& operator<<( std::ostream& ostream, TimePeriod value ); @@ -258,7 +91,7 @@ std::ostream& operator<<( std::ostream& ostream, Degree angle ); template inline void DALI_TEST_EQUALS(Type value1, Type value2, const char* location) { - if (!(value1 == value2)) + if( !CompareType(value1, value2, 0.01f) ) { std::ostringstream o; o << value1 << " == " << value2 << std::endl; @@ -514,6 +347,7 @@ struct DefaultFunctionCoverage BufferImage CreateBufferImage(); BufferImage CreateBufferImage(int width, int height, const Vector4& color); + // Prepare a resource image to be loaded. Should be called before creating the ResourceImage void PrepareResourceImage( TestApplication& application, unsigned int imageWidth, unsigned int imageHeight, Pixel::Format pixelFormat ); diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp index f6fb4bf..979e56a 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp @@ -74,6 +74,12 @@ Dali::PropertyRegistration dummyControlVisualProperty01( Dali::PropertyRegistration dummyControlVisualProperty02( typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty ); +Dali::PropertyRegistration dummyControlVisualProperty03( + typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty ); + +Dali::PropertyRegistration dummyControlVisualProperty04( + typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty ); + } DummyControl DummyControlImpl::New() @@ -144,6 +150,26 @@ Animation DummyControlImpl::CreateTransition( const Toolkit::TransitionData& tra void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value ) { + Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) ); + DummyControlImpl& dummyImpl = static_cast(control.GetImplementation()); + + switch(index) + { + case Toolkit::DummyControl::Property::TEST_VISUAL: + case Toolkit::DummyControl::Property::TEST_VISUAL2: + case Toolkit::DummyControl::Property::FOREGROUND_VISUAL: + case Toolkit::DummyControl::Property::FOCUS_VISUAL: + { + Property::Map* map = value.GetMap(); + if( map != NULL ) + { + VisualFactory visualFactory = VisualFactory::Get(); + Visual::Base visual = visualFactory.CreateVisual(*map); + dummyImpl.RegisterVisual(index, visual); + } + break; + } + } } Property::Value DummyControlImpl::GetProperty( BaseObject* object, Dali::Property::Index propertyIndex ) diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h index f27f296..75d3efe 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h @@ -46,7 +46,9 @@ public: enum Type { TEST_VISUAL = PROPERTY_START_INDEX, - TEST_VISUAL2 + TEST_VISUAL2, + FOREGROUND_VISUAL, + FOCUS_VISUAL }; }; @@ -89,7 +91,7 @@ public: void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled ); void UnregisterVisual( Property::Index index ); void EnableVisual( Property::Index index, bool enabled ); - bool IsVisualEnabled( Property::Index indepx ); + bool IsVisualEnabled( Property::Index index ); Toolkit::Visual::Base GetVisual( Property::Index index ); Animation CreateTransition( const Toolkit::TransitionData& transition ); diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h new file mode 100644 index 0000000..248276e --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h @@ -0,0 +1,199 @@ +#ifndef DALI_TEST_COMPARE_TYPES_H +#define DALI_TEST_COMPARE_TYPES_H + +/* + * Copyright (c) 2017 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 +using namespace Dali; + + +template +inline bool CompareType(Type value1, Type value2, float epsilon) +{ + return value1 == value2; +} + +/** + * A helper for fuzzy-comparing Vector2 objects + * @param[in] vector1 the first object + * @param[in] vector2 the second object + * @param[in] epsilon difference threshold + * @returns true if difference is smaller than epsilon threshold, false otherwise + */ +template <> +inline bool CompareType(float value1, float value2, float epsilon) +{ + return fabsf(value1 - value2) < epsilon; +} + +/** + * A helper for fuzzy-comparing Vector2 objects + * @param[in] vector1 the first object + * @param[in] vector2 the second object + * @param[in] epsilon difference threshold + * @returns true if difference is smaller than epsilon threshold, false otherwise + */ +template <> +inline bool CompareType(Vector2 vector1, Vector2 vector2, float epsilon) +{ + return fabsf(vector1.x - vector2.x) +inline bool CompareType(Vector3 vector1, Vector3 vector2, float epsilon) +{ + return fabsf(vector1.x - vector2.x) +inline bool CompareType(Vector4 vector1, Vector4 vector2, float epsilon) +{ + return fabsf(vector1.x - vector2.x) +inline bool CompareType(Quaternion q1, Quaternion q2, float epsilon) +{ + Quaternion q2N = -q2; // These quaternions represent the same rotation + return CompareType(q1.mVector, q2.mVector, epsilon) || CompareType(q1.mVector, q2N.mVector, epsilon); +} + +template <> +inline bool CompareType(Radian q1, Radian q2, float epsilon) +{ + return CompareType(q1.radian, q2.radian, epsilon); +} + +template <> +inline bool CompareType(Degree q1, Degree q2, float epsilon) +{ + return CompareType(q1.degree, q2.degree, epsilon); +} + +template <> +inline bool CompareType(Property::Value q1, Property::Value q2, float epsilon) +{ + Property::Type type = q1.GetType(); + if( type != q2.GetType() ) + { + return false; + } + + bool result = false; + switch(type) + { + case Property::BOOLEAN: + { + bool a, b; + q1.Get(a); + q2.Get(b); + result = a == b; + break; + } + case Property::INTEGER: + { + int a, b; + q1.Get(a); + q2.Get(b); + result = a == b; + break; + } + case Property::FLOAT: + { + float a, b; + q1.Get(a); + q2.Get(b); + result = CompareType(a, b, epsilon); + break; + } + case Property::VECTOR2: + { + Vector2 a, b; + q1.Get(a); + q2.Get(b); + result = CompareType(a, b, epsilon); + break; + } + case Property::VECTOR3: + { + Vector3 a, b; + q1.Get(a); + q2.Get(b); + result = CompareType(a, b, epsilon); + break; + } + case Property::RECTANGLE: + case Property::VECTOR4: + { + Vector4 a, b; + q1.Get(a); + q2.Get(b); + result = CompareType(a, b, epsilon); + break; + } + case Property::ROTATION: + { + Quaternion a, b; + q1.Get(a); + q2.Get(b); + result = CompareType(a, b, epsilon); + break; + } + case Property::MATRIX: + case Property::MATRIX3: + case Property::STRING: + case Property::ARRAY: + case Property::MAP: + { + //TODO: Implement this? + DALI_ASSERT_ALWAYS( 0 && "Not implemented"); + result = false; + break; + } + case Property::NONE: + { + result = false; + break; + } + } + + return result; +} + + + +#endif diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h index 9bed832..1613bb5 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h @@ -25,13 +25,15 @@ #include #include #include // for strcmp +#include // INTERNAL INCLUDES #include #include #include #include -#include "test-trace-call-stack.h" +#include +#include namespace Dali { @@ -2132,7 +2134,7 @@ private: T uniformValue; if ( GetUniformValue( program, uniform, uniformValue ) ) { - return value == uniformValue; + return CompareType(value, uniformValue, Math::MACHINE_EPSILON_10); } return false; @@ -2176,6 +2178,9 @@ private: ProgramUniformValue mProgramUniformsMat4; ProgramUniformValue mProgramUniformsMat3; + + + inline const ProgramUniformValue& GetProgramUniformsForType( const int ) const { return mProgramUniforms1i; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp index cb84952..60f4a1b 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp @@ -276,7 +276,7 @@ int UtcDaliBuilderAnimationP(void) " \"name\": \"greeting\"," " \"type\": \"TextLabel\"," " \"text\": \"Touch me\"," - " \"styles\": [\"basicText\"]," + " \"inherit\": [\"basicText\"]," " \"position\": [0, -120, 0]," " \"size\": [200, 200, 1]," " \"orientation\": [0, 0, 30]," @@ -400,7 +400,7 @@ int UtcDaliBuilderAnimationN(void) " \"name\": \"greeting\"," " \"type\": \"TextLabel\"," " \"text\": \"Touch me\"," - " \"styles\": [\"basicText\"]," + " \"inherit\": [\"basicText\"]," " \"position\": [0, -120, 0]," " \"size\": [200, 200, 1]," " \"orientation\": [0, 0, 30]," diff --git a/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp index c67b2ae..1606d71 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include #include #include diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp index 32076f1..8caf518 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -216,8 +217,12 @@ struct TestCustomControl : public Toolkit::Internal::ControlWrapper bool mNego; unsigned int mDepth; }; + } +static std::string customControlTypeName = "TestCustomControl"; +static TypeRegistration customControl( customControlTypeName, typeid(Dali::Toolkit::Control), NULL ); + int UtcDaliControlWrapperConstructor(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication @@ -227,9 +232,10 @@ int UtcDaliControlWrapperConstructor(void) DALI_TEST_CHECK( !ControlWrapper::DownCast( controlWrapper ) ); - controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); DALI_TEST_CHECK( ControlWrapper::DownCast( controlWrapper ) ); + END_TEST; } @@ -237,7 +243,7 @@ int UtcDaliControlWrapperDestructor(void) { TestApplication application; - ControlWrapper control = ControlWrapper::New( *( new Toolkit::Internal::ControlWrapper( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ) ) ); + ControlWrapper control = ControlWrapper::New( customControlTypeName, *( new Toolkit::Internal::ControlWrapper( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ) ) ); ControlWrapper control2( control ); @@ -259,7 +265,7 @@ int UtcDaliControlWrapperRelayoutRequest(void) DALI_TEST_EQUALS( gOnRelayout, false, TEST_LOCATION ); Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); Stage::GetCurrent().Add( controlWrapper ); @@ -283,7 +289,7 @@ int UtcDaliControlWrapperImplGetHeightForWidthBase(void) TestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); float width = 300.0f; float v = 0.0f; @@ -303,7 +309,7 @@ int UtcDaliControlWrapperGetWidthForHeightBase(void) TestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); float height = 300.0f; float v = 0.0f; @@ -323,7 +329,7 @@ int UtcDaliControlWrapperCalculateChildSizeBase(void) TestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); Actor child = Actor::New(); child.SetResizePolicy( Dali::ResizePolicy::FIXED, Dali::Dimension::ALL_DIMENSIONS ); @@ -344,7 +350,7 @@ int UtcDaliControlWrapperRelayoutDependentOnChildrenBase(void) TestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); bool v = false; @@ -371,7 +377,7 @@ int UtcDaliControlWrapperRegisterVisualToSelf(void) { Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); objectDestructionTracker.Start( controlWrapper ); @@ -404,7 +410,7 @@ int UtcDaliControlWrapperRegisterDisabledVisual(void) ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); Property::Index TEST_PROPERTY = 1; @@ -446,7 +452,7 @@ int UtcDaliControlWrapperRegisterUnregisterVisual(void) ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); Property::Index index = 1; @@ -491,7 +497,7 @@ int UtcDaliControlWrapperTransitionDataMap1N(void) Dali::Toolkit::TransitionData transition = TransitionData::New( map ); Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); //DummyControl actor = DummyControl::New(); controlWrapper.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); @@ -544,10 +550,56 @@ int UtcDaliControlWrapperApplyThemeStyle(void) ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); - ControlWrapper controlWrapper = ControlWrapper::New( *controlWrapperImpl ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); controlWrapperImpl->ApplyThemeStyle(); DALI_TEST_CHECK( true ); END_TEST; } + +int UtcDaliControlWrapperTestControlProperties(void) +{ + ToolkitTestApplication application; + + Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); + ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); + + Stage::GetCurrent().Add( controlWrapper ); + + // "background" property + Property::Map rendererMap; + rendererMap[Visual::Property::TYPE] = Visual::COLOR; + rendererMap[ColorVisual::Property::MIX_COLOR] = Color::RED; + controlWrapper.SetProperty( Control::Property::BACKGROUND, rendererMap ); + Property::Value propertyValue = controlWrapper.GetProperty( Control::Property::BACKGROUND ); + Property::Map* resultMap = propertyValue.GetMap(); + DALI_TEST_CHECK( resultMap->Find( Visual::Property::TYPE ) ); + DALI_TEST_EQUALS( resultMap->Find( Visual::Property::TYPE )->Get(), (int)Visual::COLOR, TEST_LOCATION ); + DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) ); + DALI_TEST_EQUALS( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get(), Color::RED, TEST_LOCATION ); + + // "keyInputFocus" property + controlWrapper.SetProperty( Control::Property::KEY_INPUT_FOCUS, true ); + DALI_TEST_EQUALS( true, controlWrapper.GetProperty( Control::Property::KEY_INPUT_FOCUS ).Get< bool >(), TEST_LOCATION ); + + // "styleName" property + controlWrapper.SetProperty( Control::Property::STYLE_NAME, "MyCustomStyle" ); + DALI_TEST_EQUALS( "MyCustomStyle", controlWrapper.GetProperty( Control::Property::STYLE_NAME ).Get< std::string >(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlWrapperTypeRegistryCreation(void) +{ + ToolkitTestApplication application; + + TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "ControlWrapper" ); + DALI_TEST_CHECK( typeInfo ) + + // Check that we can't create a ControlWrapper instance + BaseHandle baseHandle = typeInfo.CreateInstance(); + DALI_TEST_CHECK( !baseHandle ) + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp index 7d40e9e..2c395b2 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp @@ -24,7 +24,7 @@ #include #include - +#include using namespace Dali; using namespace Dali::Toolkit; @@ -609,6 +609,10 @@ int UtcDaliKeyboardFocusManagerSignalFocusedActorActivated(void) Integration::KeyEvent returnEvent("Return", "", 0, 0, 0, Integration::KeyEvent::Up); + // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager + // It makes mIsFocusIndicatorEnabled true + application.ProcessEvent(returnEvent); + // Create the first button and add it to the stage PushButton firstPushButton = PushButton::New(); firstPushButton.SetKeyboardFocusable(true); @@ -664,6 +668,10 @@ int UtcDaliKeyboardFocusManagerSignalFocusGroupChanged(void) Integration::KeyEvent tabEvent("Tab", "", 0, 0, 0, Integration::KeyEvent::Down); Integration::KeyEvent shiftTabEvent("Tab", "", 0, 1, 0, Integration::KeyEvent::Down); + // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager + // It makes mIsFocusIndicatorEnabled true + application.ProcessEvent(tabEvent); + // Send the tab event to change focus group in the forward direction application.ProcessEvent(tabEvent); DALI_TEST_CHECK(focusGroupChangedCallback.mSignalVerified); @@ -787,6 +795,10 @@ int UtcDaliKeyboardFocusManagerChangeFocusDirectionByKeyEvents(void) Integration::KeyEvent pageUpEvent("Prior", "", 0, 0, 0, Integration::KeyEvent::Down); Integration::KeyEvent pageDownEvent("Next", "", 0, 0, 0, Integration::KeyEvent::Down); + // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager + // It makes mIsFocusIndicatorEnabled true + application.ProcessEvent(leftEvent); + // Create a 2x2 table view and try to move focus inside it TableView tableView = TableView::New( 2, 2 ); Stage::GetCurrent().Add(tableView); @@ -899,3 +911,214 @@ int UtcDaliKeyboardFocusManagerChangeFocusDirectionByKeyEvents(void) } + + + +int UtcDaliKeyboardFocusManagerMoveFocusTestStateChange(void) +{ + ToolkitTestApplication application; + + tet_infoline(" UtcDaliKeyboardFocusManagerMoveFocusTestStateChange"); + + // Register Type + TypeInfo type; + type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" ); + DALI_TEST_CHECK( type ); + BaseHandle handle = type.CreateInstance(); + DALI_TEST_CHECK( handle ); + + KeyboardFocusManager manager = KeyboardFocusManager::Get(); + DALI_TEST_CHECK(manager); + + bool preFocusChangeSignalVerified = false; + PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified); + manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback ); + + bool focusChangedSignalVerified = false; + FocusChangedCallback focusChangedCallback(focusChangedSignalVerified); + manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback ); + + // Create the first actor and add it to the stage + Control first = Control::New(); + first.SetKeyboardFocusable(true); + Stage::GetCurrent().Add(first); + + // Create the second actor and add it to the stage + Control second = Control::New(); + second.SetKeyboardFocusable(true); + Stage::GetCurrent().Add(second); + + // Move the focus to the right + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false); + + // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal + DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified); + DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor()); + DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor()); + DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT); + preFocusChangeCallback.Reset(); + + // Check that the focus is set on the first actor + DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor()); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + focusChangedCallback.Reset(); + + // Move the focus towards right + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false); + + // Because no layout control in the stage and the first actor is focused, it should emit the PreFocusChange signal + DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified); + DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first); + DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor()); + DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT); + preFocusChangeCallback.Reset(); + + // Check that the focus is set on the second actor + DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + focusChangedCallback.Reset(); + + // Move the focus towards up + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == false); + + // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal + DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified); + DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == second); + DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor()); + DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::UP); + preFocusChangeCallback.Reset(); + DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified); + + // Create a 2x2 table view and try to move focus inside it + TableView tableView = TableView::New( 2, 2 ); + Stage::GetCurrent().Add(tableView); + + // Create the third actor + Control third = Control::New(); + third.SetKeyboardFocusable(true); + + // Create the fourth actor + Control fourth = Control::New(); + fourth.SetKeyboardFocusable(true); + + // Add the four children to table view + tableView.AddChild(first, TableView::CellPosition(0, 0)); + tableView.AddChild(second, TableView::CellPosition(0, 1)); + tableView.AddChild(third, TableView::CellPosition(1, 0)); + tableView.AddChild(fourth, TableView::CellPosition(1, 1)); + + // Set the focus to the first actor + DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first); + + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + + focusChangedCallback.Reset(); + + // Move the focus towards right + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + + focusChangedCallback.Reset(); + + // Move the focus towards down + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth); + + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + + focusChangedCallback.Reset(); + + // Move the focus towards left + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == fourth); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == third); + + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + + focusChangedCallback.Reset(); + + // Move the focus towards up + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == third); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + focusChangedCallback.Reset(); + + // Move the focus towards left. The focus move will fail as no way to move it upwards + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == false); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); + DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified); + DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first); + DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor()); + DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::LEFT); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + + preFocusChangeCallback.Reset(); + DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified); + + // Enable the loop + manager.SetFocusGroupLoop(true); + DALI_TEST_CHECK(manager.GetFocusGroupLoop() == true); + + // Move the focus towards left again. The focus should move to the fourth actor. + DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true); + DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth); + DALI_TEST_CHECK(focusChangedCallback.mSignalVerified); + DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first); + DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth); + + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "FOCUSED", TEST_LOCATION ); + + focusChangedCallback.Reset(); + + // Clear the focus + manager.ClearFocus(); + DALI_TEST_EQUALS(first.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(second.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(third.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + DALI_TEST_EQUALS(fourth.GetProperty(DevelControl::Property::STATE), "NORMAL", TEST_LOCATION ); + + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp index 6bd2c05..cd38bc3 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp @@ -916,11 +916,11 @@ int UtcDaliPopupPropertyContextualMode(void) // Test all contextual modes. const char* mode[5] = { "NON_CONTEXTUAL", "ABOVE", "RIGHT", "BELOW", "LEFT" }; Vector2 offsetValues[5]; - offsetValues[0] = Vector2( 0.0f, 0.0f ); - offsetValues[1] = Vector2( 0.0f, -10.0f ); - offsetValues[2] = Vector2( 10.0f, 0.0f ); - offsetValues[3] = Vector2( 0.0f, 10.0f ); - offsetValues[4] = Vector2( -10.0f, 0.0f ); + offsetValues[0] = Vector2( 0.375f, 0.0f ); + offsetValues[1] = Vector2( -0.125f, -10.5f ); + offsetValues[2] = Vector2( 10.875f, -0.5f ); + offsetValues[3] = Vector2( -0.125f, 10.5f ); + offsetValues[4] = Vector2( -10.875f, -0.5f ); for( int i = 0; i < 5; ++i ) { diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp index 2cee1b5..9b7c6fc 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp @@ -25,6 +25,13 @@ using namespace Dali; using namespace Toolkit; +namespace +{ + +const char* TEST_IMAGE_FILE_NAME = "selection-popup-border.9.png"; + +} + void dali_textselectionpopup_startup(void) { test_return_value = TET_UNDEF; @@ -107,11 +114,37 @@ int UtcDaliToolkitTextSelectionPopupDownCastP(void) END_TEST; } +int UtcDaliToolkitTextSelectionPopupBackgroundBorderP(void) +{ + ToolkitTestApplication application; + TextSelectionPopup textSelectionPopup; + textSelectionPopup = TextSelectionPopup::New( NULL ); + + textSelectionPopup.SetProperty( TextSelectionPopup::Property::BACKGROUND_BORDER, + Property::Map().Add( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ) ); + + Property::Value value = textSelectionPopup.GetProperty( TextSelectionPopup::Property::BACKGROUND_BORDER ); + + Property::Map map; + value.Get( map ); + + Property::Value* returnValue = map.Find( Dali::Toolkit::ImageVisual::Property::URL ); + DALI_TEST_CHECK( NULL != returnValue ); + + if( returnValue ) + { + std::string url; + returnValue->Get( url ); + DALI_TEST_EQUALS( TEST_IMAGE_FILE_NAME, url, TEST_LOCATION ); + } + + END_TEST; +} + // TextSelectionToolBar is used TextSelectionPopup, below tests it individually int UtcDaliToolkitTextSelectionToolBarP(void) { - // Creates Toolbar, adds 2 options and a divider then resizes divider ToolkitTestApplication application; @@ -140,3 +173,27 @@ int UtcDaliToolkitTextSelectionToolBarP(void) DALI_TEST_CHECK( toolbar ); END_TEST; } + +int UtcDaliToolkitTextSelectionToolBarScrollBarP(void) +{ + // Creates Toolbar, adds 2 options and a divider then resizes divider + ToolkitTestApplication application; + + TextSelectionToolbar toolbar = TextSelectionToolbar::New(); + + toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, Size( 100.0f, 60.0f) ); + + Toolkit::PushButton option = Toolkit::PushButton::New(); + option.SetName( "test-option" ); + option.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS ); + toolbar.AddOption( option ); + + // Add a scroll-bar + toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR, true ); + + bool enabled = toolbar.GetProperty( Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR ); + DALI_TEST_CHECK( enabled ); + + DALI_TEST_CHECK( toolbar ); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp index 5ca2b17..de4c4dd 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "dummy-control.h" using namespace Dali; @@ -254,10 +255,12 @@ int UtcDaliTransitionDataMap1P(void) Renderer renderer = actor.GetRendererAt(0); Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIndex = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); application.SendNotification(); application.Render(0); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Color::MAGENTA, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION ); anim.Play(); @@ -265,15 +268,19 @@ int UtcDaliTransitionDataMap1P(void) application.Render(500); // Start animation application.Render(500); // Halfway thru anim application.SendNotification(); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), (Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION ); application.Render(500); // End of anim application.SendNotification(); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Color::RED, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::RED), TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION ); END_TEST; } + + int UtcDaliTransitionDataMap2P(void) { TestApplication application; @@ -282,7 +289,6 @@ int UtcDaliTransitionDataMap2P(void) Property::Map map; map["target"] = "visual1"; - //Control::CONTROL_PROPERTY_END_INDEX + 1 map["property"] = ColorVisual::Property::MIX_COLOR; map["initialValue"] = Color::MAGENTA; map["targetValue"] = Color::RED; @@ -316,10 +322,83 @@ int UtcDaliTransitionDataMap2P(void) Renderer renderer = actor.GetRendererAt(0); Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIndex = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); + application.SendNotification(); + application.Render(0); + + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); + + anim.Play(); + + application.SendNotification(); + application.Render(0); + application.Render(500); // Start animation + application.Render(500); // Halfway thru anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); + + application.Render(500); // End of anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::RED), TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); + + END_TEST; +} + + +int UtcDaliTransitionDataMap2Pb(void) +{ + TestApplication application; + + tet_printf("Testing animation of a visual property using programmatic maps\n"); + + Property::Map map; + map["target"] = "visual1"; + map["property"] = PrimitiveVisual::Property::MIX_COLOR; + map["initialValue"] = Color::MAGENTA; + map["targetValue"] = Color::RED; + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.5f) + .Add("duration", 1.0f)); + + Dali::Toolkit::TransitionData transition = TransitionData::New( map ); + + DummyControl actor = DummyControl::New(); + actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + actor.SetName("Actor1"); + actor.SetColor(Color::CYAN); + Stage::GetCurrent().Add(actor); + + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + + Property::Map visualMap; + visualMap[Visual::Property::TYPE] = Visual::PRIMITIVE; + visualMap[PrimitiveVisual::Property::MIX_COLOR] = Color::MAGENTA; + visualMap[ PrimitiveVisual::Property::SHAPE ] = PrimitiveVisual::Shape::SPHERE; + visualMap[ PrimitiveVisual::Property::SLICES ] = 10; + visualMap[ PrimitiveVisual::Property::STACKS ] = 10; + + Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap ); + visual.SetName( "visual1" ); + + Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1; + dummyImpl.RegisterVisual( visualIndex, visual ); + + Animation anim = dummyImpl.CreateTransition( transition ); + DALI_TEST_CHECK( anim ); + + Renderer renderer = actor.GetRendererAt(0); + Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, PrimitiveVisual::Property::MIX_COLOR ); + Property::Index opacityIndex = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); application.SendNotification(); application.Render(0); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Color::MAGENTA, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); anim.Play(); @@ -328,15 +407,18 @@ int UtcDaliTransitionDataMap2P(void) application.Render(500); // Start animation application.Render(500); // Halfway thru anim application.SendNotification(); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), (Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); application.Render(500); // End of anim application.SendNotification(); - DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Color::RED, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::RED), TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION); END_TEST; } + int UtcDaliTransitionDataMap3P(void) { TestApplication application; @@ -464,6 +546,146 @@ int UtcDaliTransitionDataMap4P(void) END_TEST; } +int UtcDaliTransitionDataMap5P(void) +{ + TestApplication application; + + tet_printf("Testing animation visual opacity using stylesheet equivalent maps\n"); + + Property::Map map; + map["target"] = "visual1"; + map["property"] = "opacity"; + map["initialValue"] = 0.0f; + map["targetValue"] = 1.0f; + map["animator"] = Property::Map() + .Add("alphaFunction", "EASE_IN_OUT") + .Add("timePeriod", Property::Map() + .Add("delay", 0.5f) + .Add("duration", 1.0f)); + + Dali::Toolkit::TransitionData transition = TransitionData::New( map ); + + DummyControl actor = DummyControl::New(); + actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + actor.SetName("Actor1"); + actor.SetColor(Color::CYAN); + Stage::GetCurrent().Add(actor); + + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + + Property::Map visualMap; + visualMap[Visual::Property::TYPE] = Visual::COLOR; + visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA; + Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap ); + visual.SetName( "visual1" ); + + Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1; + dummyImpl.RegisterVisual( visualIndex, visual ); + + Animation anim = dummyImpl.CreateTransition( transition ); + DALI_TEST_CHECK( anim ); + + Renderer renderer = actor.GetRendererAt(0); + Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIndex = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); + application.SendNotification(); + application.Render(0); + + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 0.0f, 0.001f, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION ); + + anim.Play(); + + application.SendNotification(); + application.Render(500); // Start animation + application.Render(500); // Halfway thru anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 0.5f, 0.001f, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION ); + + application.Render(501); // End of anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::AUTO, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliTransitionDataMap6P(void) +{ + TestApplication application; + + tet_printf("Testing animation visual opacity using stylesheet equivalent maps\n"); + + Property::Map map; + map["target"] = "visual1"; + map["property"] = "opacity"; + map["targetValue"] = 0.0f; + map["animator"] = Property::Map() + .Add("alphaFunction", "EASE_IN_OUT") + .Add("timePeriod", Property::Map() + .Add("delay", 0.5f) + .Add("duration", 1.0f)); + + Dali::Toolkit::TransitionData transition = TransitionData::New( map ); + + DummyControl actor = DummyControl::New(); + actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + actor.SetName("Actor1"); + actor.SetColor(Color::CYAN); + Stage::GetCurrent().Add(actor); + + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + + Property::Map visualMap; + visualMap[Visual::Property::TYPE] = Visual::COLOR; + visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA; + Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap ); + visual.SetName( "visual1" ); + + Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1; + dummyImpl.RegisterVisual( visualIndex, visual ); + + Animation anim = dummyImpl.CreateTransition( transition ); + DALI_TEST_CHECK( anim ); + + Renderer renderer = actor.GetRendererAt(0); + Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIndex = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); + application.SendNotification(); + application.Render(0); + + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 1.0f, 0.001f, TEST_LOCATION ); + + // Note, This should be testing for AUTO + // this is the same problem as C# target value being set before Play is called. + // @todo How was this solved? + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION ); + + anim.Play(); + + application.SendNotification(); + application.Render(500); // Start animation + application.Render(500); // Halfway thru anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 0.5f, 0.001f, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION ); + + application.Render(500); // End of anim + application.SendNotification(); + DALI_TEST_EQUALS( renderer.GetProperty(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(opacityIndex), 0.0f, 0.001f, TEST_LOCATION ); + DALI_TEST_EQUALS( renderer.GetProperty(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION ); + + END_TEST; +} + int UtcDaliTransitionDataMap1N(void) { @@ -506,8 +728,8 @@ int UtcDaliTransitionDataMapN3(void) Property::Map map; map["target"] = "visual1"; map["property"] = "mixColor"; - map["initialValue"] = Color::MAGENTA; - map["targetValue"] = Color::RED; + map["initialValue"] = Vector3(Color::MAGENTA); + map["targetValue"] = Vector3(Color::RED); map["animator"] = Property::Map() .Add("alphaFunction", "EASE_OUT_BACK") .Add("timePeriod", Property::Map() @@ -526,7 +748,7 @@ int UtcDaliTransitionDataMapN3(void) DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); Property::Map visualMap; visualMap[Visual::Property::TYPE] = Visual::COLOR; - visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA; + visualMap[ColorVisual::Property::MIX_COLOR] = Vector3(Color::MAGENTA); Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap ); visual.SetName( "visual1" ); @@ -548,8 +770,8 @@ int UtcDaliTransitionDataMapN4(void) Property::Map map; map["target"] = "visual1"; map["property"] = "mixColor"; - map["initialValue"] = Color::MAGENTA; - map["targetValue"] = Color::RED; + map["initialValue"] = Vector3(Color::MAGENTA); + map["targetValue"] = Vector3(Color::RED); map["animator"] = Property::Map() .Add("alphaFunction", Vector3(.1f,1.0f,0.5f)) .Add("timePeriod", Property::Map() @@ -583,9 +805,11 @@ int UtcDaliTransitionDataMapN4(void) Renderer renderer = actor.GetRendererAt(0); Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIdx = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); tet_printf( "Test that the property has been set to target value\n"); - DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Color::RED, 0.001, TEST_LOCATION); + DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION); + DALI_TEST_EQUALS(renderer.GetProperty(opacityIdx), 1.0f, 0.001, TEST_LOCATION); END_TEST; } @@ -636,7 +860,7 @@ int UtcDaliTransitionDataMapN5(void) Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); tet_printf( "Test that the property has been set to target value\n"); - DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Color::RED, 0.001, TEST_LOCATION); + DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION); END_TEST; } @@ -685,9 +909,11 @@ int UtcDaliTransitionDataMapN6(void) Renderer renderer = actor.GetRendererAt(0); Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index opacityIdx = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); tet_printf( "Test that the property has been set to target value\n"); - DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Color::RED, 0.001, TEST_LOCATION); + DALI_TEST_EQUALS(renderer.GetProperty(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION); + DALI_TEST_EQUALS(renderer.GetProperty(opacityIdx), 1.0f, 0.001, TEST_LOCATION); END_TEST; } @@ -852,7 +1078,8 @@ int UtcDaliTransitionDataGetAnimatorP(void) Property::Map map8; map8["target"] = "Visual1"; - map8["property"] = "colorAlpha"; + map8["property"] = "opacity"; + map8["initialValue"] = 0.0f; map8["targetValue"] = 1.0f; map8["animator"] = Property::Map() .Add("alphaFunction", "EASE_IN") diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp index f0175c4..fc94130 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp @@ -119,9 +119,21 @@ static void TestMixColor( Visual::Base visual, Property::Index mixColorIndex, co visual.CreatePropertyMap(map); Property::Value* value = map.Find( mixColorIndex ); DALI_TEST_CHECK( value ); - Vector4 mixColor; - DALI_TEST_CHECK( value->Get( mixColor ) ); - DALI_TEST_EQUALS( mixColor, testColor, 0.001, TEST_LOCATION ); + Vector3 mixColor1; + DALI_TEST_CHECK( value->Get( mixColor1 ) ); + DALI_TEST_EQUALS( mixColor1, Vector3(testColor), 0.001, TEST_LOCATION ); + + value = map.Find( DevelVisual::Property::MIX_COLOR ); + DALI_TEST_CHECK( value ); + Vector4 mixColor2; + DALI_TEST_CHECK( value->Get( mixColor2 ) ); + DALI_TEST_EQUALS( mixColor2, testColor, 0.001, TEST_LOCATION ); + + value = map.Find( DevelVisual::Property::OPACITY ); + DALI_TEST_CHECK( value ); + float opacity; + DALI_TEST_CHECK( value->Get( opacity ) ); + DALI_TEST_EQUALS( opacity, testColor.a, 0.001, TEST_LOCATION ); } @@ -286,19 +298,6 @@ int UtcDaliVisualSize(void) svgVisual2.GetNaturalSize(naturalSize); DALI_TEST_EQUALS( naturalSize, Vector2(100.f, 100.f), TEST_LOCATION ); // Natural size should still be 100, 100 - // Batch Image visual - TestPlatformAbstraction& platform = application.GetPlatform(); - Vector2 testSize(80.f, 160.f); - platform.SetClosestImageSize(testSize); - propertyMap.Clear(); - propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); - propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); - propertyMap.Insert( "batchingEnabled", true ); - Visual::Base batchImageVisual = factory.CreateVisual( propertyMap ); - batchImageVisual.SetTransformAndSize(DefaultTransform(), controlSize ); - batchImageVisual.GetNaturalSize( naturalSize ); - DALI_TEST_EQUALS( naturalSize, Vector2( 80.0f, 160.0f ), TEST_LOCATION ); - // Text visual. // Load some fonts to get the same metrics on different platforms. @@ -957,45 +956,6 @@ int UtcDaliVisualGetPropertyMap9(void) END_TEST; } -int UtcDaliVisualGetPropertyMapBatchImageVisual(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualGetPropertyMapBatchImageVisual:" ); - - VisualFactory factory = VisualFactory::Get(); - Property::Map propertyMap; - propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); - propertyMap.Insert( ImageVisual::Property::BATCHING_ENABLED, true ); - propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); - propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 20 ); - propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 30 ); - - Visual::Base batchImageVisual = factory.CreateVisual( propertyMap ); - DALI_TEST_CHECK( batchImageVisual ); - - Property::Map resultMap; - batchImageVisual.CreatePropertyMap( resultMap ); - - // Check the property values from the returned map from visual - Property::Value* value = resultMap.Find( Visual::Property::TYPE, Property::INTEGER ); - DALI_TEST_CHECK( value ); - DALI_TEST_CHECK( value->Get() == Visual::IMAGE ); - - value = resultMap.Find( ImageVisual::Property::URL, Property::STRING ); - DALI_TEST_CHECK( value ); - DALI_TEST_CHECK( value->Get() == TEST_IMAGE_FILE_NAME ); - - value = resultMap.Find( ImageVisual::Property::DESIRED_WIDTH, Property::INTEGER ); - DALI_TEST_CHECK( value ); - DALI_TEST_CHECK( value->Get() == 20 ); - - value = resultMap.Find( ImageVisual::Property::DESIRED_HEIGHT, Property::INTEGER ); - DALI_TEST_CHECK( value ); - DALI_TEST_CHECK( value->Get() == 30 ); - - END_TEST; -} - //Text shape visual int UtcDaliVisualGetPropertyMap10(void) { @@ -1117,36 +1077,6 @@ int UtcDaliVisualGetPropertyMap11(void) END_TEST; } -int UtcDaliVisualGetPropertyMapBatchImageVisualNoAtlas(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualGetPropertyMapBatchImageVisualNoAtlas:" ); - - VisualFactory factory = VisualFactory::Get(); - Property::Map propertyMap; - propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); - propertyMap.Insert( ImageVisual::Property::BATCHING_ENABLED, true ); - propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); - - // Set the desired size to be larger than the atlas limit of 1024x1024. - propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 2048 ); - propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 2048 ); - - // Create the visual. - Visual::Base batchImageVisual = factory.CreateVisual( propertyMap ); - - DALI_TEST_CHECK( batchImageVisual ); - - DummyControl dummyControl = DummyControl::New(true); - Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); - dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, batchImageVisual ); - Stage::GetCurrent().Add( dummyControl ); - - DALI_TEST_CHECK( dummyControl.GetRendererCount() == 1u ); - - END_TEST; -} - int UtcDaliVisualAnimateBorderVisual01(void) { ToolkitTestApplication application; @@ -1201,12 +1131,13 @@ int UtcDaliVisualAnimateBorderVisual01(void) DALI_TEST_EQUALS( color, testColor, TEST_LOCATION ); DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("borderColor", testColor ), true, TEST_LOCATION ); - color = renderer.GetProperty( mixColorIndex ); + color = renderer.GetProperty( mixColorIndex ); testColor = Vector4( 1,1,1,0.4f ); - DALI_TEST_EQUALS( color, testColor, 0.0001f, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", testColor ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( Vector3(color), Vector3(testColor), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(testColor) ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", testColor.a ) , true, TEST_LOCATION ); - application.Render(2000u); // halfway point between blue and white + application.Render(2000u); color = renderer.GetProperty( borderColorIndex ); DALI_TEST_EQUALS( color, Color::WHITE, TEST_LOCATION ); @@ -1215,7 +1146,8 @@ int UtcDaliVisualAnimateBorderVisual01(void) color = renderer.GetProperty( mixColorIndex ); testColor = Vector4(1,1,1,0); DALI_TEST_EQUALS( color, testColor, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", testColor ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(testColor) ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", testColor.a ), true, TEST_LOCATION ); END_TEST; } @@ -1287,31 +1219,31 @@ int UtcDaliVisualAnimateColorVisual(void) DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION); Renderer renderer = actor.GetRendererAt(0); - Property::Index index = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); + Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR ); Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::AUTO, TEST_LOCATION ); Animation animation = Animation::New(4.0f); - animation.AnimateTo( Property(renderer, index), Color::WHITE ); + animation.AnimateTo( Property(renderer, mixColorIndex), Vector3(Color::WHITE) ); animation.Play(); application.SendNotification(); application.Render(0); application.Render(2000u); // halfway point - Vector4 color = renderer.GetProperty( index ); - Vector4 testColor = (Color::BLUE + Color::WHITE)*0.5f; + Vector3 color = renderer.GetProperty( mixColorIndex ); + Vector3 testColor = Vector3(Color::BLUE + Color::WHITE)*0.5f; DALI_TEST_EQUALS( color, testColor, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", testColor ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", testColor ), true, TEST_LOCATION ); application.Render(2000u); // halfway point between blue and white - color = renderer.GetProperty( index ); - DALI_TEST_EQUALS( color, Color::WHITE, TEST_LOCATION ); + color = renderer.GetProperty( mixColorIndex ); + DALI_TEST_EQUALS( color, Vector3(Color::WHITE), TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Color::WHITE ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(Color::WHITE) ), true, TEST_LOCATION ); blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::AUTO, TEST_LOCATION ); @@ -1379,14 +1311,16 @@ int UtcDaliVisualAnimatePrimitiveVisual(void) DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("uColor", Vector4(0.5f, 0.5f, 0.5f, 1.0f )), true, TEST_LOCATION ); Vector4 halfwayColor = (INITIAL_MIX_COLOR + TARGET_MIX_COLOR)*0.5; - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", halfwayColor ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(halfwayColor) ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", halfwayColor.a ), true, TEST_LOCATION ); application.Render(2001u); // go past end application.SendNotification(); // Trigger signals DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION ); DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("uColor", Color::WHITE ), true, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", TARGET_MIX_COLOR ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(TARGET_MIX_COLOR) ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", TARGET_MIX_COLOR.a ), true, TEST_LOCATION ); blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::AUTO, TEST_LOCATION ); @@ -1457,15 +1391,18 @@ int UtcDaliVisualAnimateImageVisualMixColor(void) application.SendNotification(); application.Render(0); application.Render(2000u); // halfway point + Vector4 testColor(1.0f, 0.0f, 0.5f, 0.75f ); DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("uColor", Vector4(0.5f, 0.5f, 0.5f, 1.0f )), true, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector4(1.0f, 0.0f, 0.5f, 0.75f )), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(testColor)), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", testColor.a), true, TEST_LOCATION ); application.Render(2000u); // halfway point between blue and white DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION ); DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("uColor", Color::WHITE ), true, TEST_LOCATION ); - DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", TARGET_MIX_COLOR), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("mixColor", Vector3(TARGET_MIX_COLOR)), true, TEST_LOCATION ); + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", TARGET_MIX_COLOR.a), true, TEST_LOCATION ); TestMixColor( visual, DevelVisual::Property::MIX_COLOR, TARGET_MIX_COLOR ); @@ -1475,6 +1412,116 @@ int UtcDaliVisualAnimateImageVisualMixColor(void) END_TEST; } + +int UtcDaliVisualAnimateImageVisualOpacity(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliAnimateImageVisual mix color" ); + + application.GetPlatform().SetClosestImageSize( Vector2(100, 100) ); + + VisualFactory factory = VisualFactory::Get(); + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + propertyMap.Insert("opacity", 0.5f); + propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true); + Visual::Base visual = factory.CreateVisual( propertyMap ); + + DummyControl actor = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + actor.SetSize(2000, 2000); + actor.SetParentOrigin(ParentOrigin::CENTER); + actor.SetColor(Color::BLACK); + Stage::GetCurrent().Add(actor); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION); + + Renderer renderer = actor.GetRendererAt(0); + tet_infoline("Test that the renderer has the opacity property"); + Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY ); + DALI_TEST_CHECK( index != Property::INVALID_INDEX ); + + + Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); + DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::ON, TEST_LOCATION ); + + { + tet_infoline( "Test that the opacity can be increased to full via animation, and that the blend mode is set appropriately at the start and end of the animation." ); + + Property::Map map; + map["target"] = "testVisual"; + map["property"] = "opacity"; + map["targetValue"] = 1.0f; + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 4.0f)); + + Dali::Toolkit::TransitionData transition = TransitionData::New( map ); + Animation animation = dummyImpl.CreateTransition( transition ); + animation.Play(); + + application.SendNotification(); + application.Render(0); + application.Render(2000u); // halfway point + application.SendNotification(); + + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", 0.75f), true, TEST_LOCATION ); + + application.Render(2001u); // end + application.SendNotification(); + + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", 1.0f), true, TEST_LOCATION ); + + blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); + DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::AUTO, TEST_LOCATION ); + } + + + { + tet_infoline( "Test that the opacity can be reduced via animation, and that the blend mode is set appropriately at the start and end of the animation." ); + + Property::Map map; + map["target"] = "testVisual"; + map["property"] = DevelVisual::Property::OPACITY; + map["targetValue"] = 0.1f; + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 4.0f)); + + Dali::Toolkit::TransitionData transition = TransitionData::New( map ); + Animation animation = dummyImpl.CreateTransition( transition ); + animation.Play(); + + blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); + DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::ON, TEST_LOCATION ); + + application.SendNotification(); + application.Render(0); + application.Render(2000u); // halfway point + application.SendNotification(); + + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", 0.55f), true, TEST_LOCATION ); + + application.Render(2016u); // end + application.SendNotification(); + + DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue("opacity", 0.1f), true, TEST_LOCATION ); + + blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE ); + DALI_TEST_EQUALS( blendModeValue.Get(), (int)BlendMode::ON, TEST_LOCATION ); + } + + + END_TEST; +} + int UtcDaliVisualAnimateImageVisualPixelArea(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index 48de1ca..ab0f0cd 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -330,10 +330,13 @@ int UtcDaliVisualFactoryGetColorVisual1(void) DummyControl actor = DummyControl::New(); TestVisualRender( application, actor, visual ); - Vector4 actualValue(Vector4::ZERO); + Vector3 actualValue(Vector4::ZERO); + float opacity=0.0f; TestGlAbstraction& gl = application.GetGlAbstraction(); - DALI_TEST_CHECK( gl.GetUniformValue( "mixColor", actualValue ) ); - DALI_TEST_EQUALS( actualValue, testColor, TEST_LOCATION ); + DALI_TEST_CHECK( gl.GetUniformValue( "mixColor", actualValue ) ); + DALI_TEST_CHECK( gl.GetUniformValue( "opacity", opacity ) ); + DALI_TEST_EQUALS( actualValue, Vector3(testColor), TEST_LOCATION ); + DALI_TEST_EQUALS( opacity, testColor.a, TEST_LOCATION ); END_TEST; } @@ -356,10 +359,13 @@ int UtcDaliVisualFactoryGetColorVisual2(void) DummyControl actor = DummyControl::New(); TestVisualRender( application, actor, visual ); - Vector4 actualValue(Vector4::ZERO); + Vector3 actualValue; + float opacity; TestGlAbstraction& gl = application.GetGlAbstraction(); - DALI_TEST_CHECK( gl.GetUniformValue( "mixColor", actualValue ) ); - DALI_TEST_EQUALS( actualValue, testColor, TEST_LOCATION ); + DALI_TEST_CHECK( gl.GetUniformValue( "mixColor", actualValue ) ); + DALI_TEST_CHECK( gl.GetUniformValue( "opacity", opacity ) ); + DALI_TEST_EQUALS( actualValue, Vector3(testColor), TEST_LOCATION ); + DALI_TEST_EQUALS( opacity, testColor.a, TEST_LOCATION ); Stage::GetCurrent().Remove(actor); DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); @@ -1976,142 +1982,6 @@ int UtcDaliVisualFactoryGetPrimitiveVisualN1(void) END_TEST; } -int UtcDaliVisualFactoryGetBatchImageVisual1(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetBatchImageVisual1: Request a Batch Image visual with a Property::Map" ); - - VisualFactory factory = VisualFactory::Get(); - DALI_TEST_CHECK( factory ); - - Property::Map propertyMap; - propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); - propertyMap.Insert( ImageVisual::Property::BATCHING_ENABLED, true ); - propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); - - Visual::Base visual = factory.CreateVisual( propertyMap ); - DALI_TEST_CHECK( visual ); - - DummyControl actor = DummyControl::New(); - DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); - dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual ); - - actor.SetSize( 200.0f, 200.0f ); - Stage::GetCurrent().Add( actor ); - visual.SetTransformAndSize(DefaultTransform(), Vector2( 200.0f, 200.0f ) ); - - // Test SetOnStage(). - DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); - - application.SendNotification(); - application.Render(); - - // Test SetOffStage(). - actor.Unparent(); - DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); - - END_TEST; -} - -int UtcDaliVisualFactoryGetBatchImageVisual2(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetBatchImageVisual2: Request Batch Image visual from an Image Visual with batchingEnabled set" ); - - VisualFactory factory = VisualFactory::Get(); - DALI_TEST_CHECK( factory ); - - Property::Map propertyMap; - // Create a normal Image Visual. - propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); - // Instruct the factory to change Image Visuals to Batch-Image Visuals. - propertyMap.Insert( ImageVisual::Property::BATCHING_ENABLED, true ); - - // Properties for the Batch-Image Visual. - propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); - - Visual::Base visual = factory.CreateVisual( propertyMap ); - DALI_TEST_CHECK( visual ); - - // Check that a Batch-Image visual was created instead of an Image visual. - Property::Map resultMap; - visual.CreatePropertyMap( resultMap ); - - Property::Value* value = resultMap.Find( Visual::Property::TYPE, Property::INTEGER ); - DALI_TEST_CHECK( value ); - DALI_TEST_EQUALS( value->Get(), (int)Visual::IMAGE, TEST_LOCATION ); - - DummyControl actor = DummyControl::New(); - DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); - dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual ); - - actor.SetSize( 200.0f, 200.0f ); - Stage::GetCurrent().Add( actor ); - visual.SetTransformAndSize(DefaultTransform(), Vector2( 200.0f, 200.0f ) ); - - // Test SetOnStage(). - DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); - - application.SendNotification(); - application.Render(); - - // Test SetOffStage(). - actor.Unparent(); - DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); - - END_TEST; -} - -int UtcDaliVisualFactoryGetBatchImageVisual3(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetBatchImageVisual3: Create an ImageView that uses a batched visual internally" ); - - VisualFactory factory = VisualFactory::Get(); - DALI_TEST_CHECK( factory ); - - // Create a property-map that enables batching. - Property::Map propertyMap; - propertyMap[ Dali::Toolkit::ImageVisual::Property::URL ] = TEST_IMAGE_FILE_NAME ; - propertyMap[ "desiredHeight" ] = 200; - propertyMap[ "desiredWidth" ] = 200; - propertyMap[ "batchingEnabled" ] = true; - - // Create an ImageView, passing the property-map in to instruct it to use batching. - Toolkit::ImageView imageView = Toolkit::ImageView::New(); - imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, propertyMap ); - - imageView.SetSize( 200.0f, 200.0f ); - Stage::GetCurrent().Add( imageView ); - - END_TEST; -} - -int UtcDaliVisualFactoryGetBatchImageVisual4N(void) -{ - ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetBatchImageVisual4: Create an ImageView that uses a batched visual, with desired properties of the wrong type" ); - - VisualFactory factory = VisualFactory::Get(); - DALI_TEST_CHECK( factory ); - - // Create a property-map that enables batching. - Property::Map propertyMap; - propertyMap[ Dali::Toolkit::ImageVisual::Property::URL ] = TEST_IMAGE_FILE_NAME ; - propertyMap[ "desiredHeight" ] = Vector2(100, 100); - propertyMap[ "desiredWidth" ] = Vector3(1, 1, 1); - propertyMap[ "batchingEnabled" ] = true; - - // Create an ImageView, passing the property-map in to instruct it to use batching. - Toolkit::ImageView imageView = Toolkit::ImageView::New(); - imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, propertyMap ); - - imageView.SetSize( 200.0f, 200.0f ); - Stage::GetCurrent().Add( imageView ); - - END_TEST; -} - int UtcDaliVisualFactoryGetAnimatedImageVisual1(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/devel-api/builder/tree-node.cpp b/dali-toolkit/devel-api/builder/tree-node.cpp index 6b0f6b3..3d9eed7 100644 --- a/dali-toolkit/devel-api/builder/tree-node.cpp +++ b/dali-toolkit/devel-api/builder/tree-node.cpp @@ -23,7 +23,8 @@ #include "dali-toolkit/devel-api/builder/tree-node.h" #include "dali-toolkit/internal/builder/tree-node-manipulator.h" -namespace + +namespace Dali { bool CaseInsensitiveCharacterCompare( unsigned char a, unsigned char b ) @@ -45,12 +46,6 @@ bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b ) return result; } -} // anonymous namespace - - -namespace Dali -{ - namespace Toolkit { diff --git a/dali-toolkit/devel-api/controls/control-devel.h b/dali-toolkit/devel-api/controls/control-devel.h index 71071db..306ce2d 100644 --- a/dali-toolkit/devel-api/controls/control-devel.h +++ b/dali-toolkit/devel-api/controls/control-devel.h @@ -30,6 +30,13 @@ namespace Toolkit namespace DevelControl { +enum State +{ + NORMAL, + FOCUSED, + DISABLED +}; + namespace Property { @@ -53,6 +60,22 @@ enum * @see Toolkit::Tooltip */ TOOLTIP = BACKGROUND + 1, + + /** + * @brief The current state of the control. + * @details Name "state", type DevelControl::State ( Property::INTEGER ) or Property::STRING + * + * @see DevelControl::State + */ + STATE = BACKGROUND + 2, + + /** + * @brief The current sub state of the control. + * @details Name "subState", type Property::INTEGER or Property::STRING. The enumeration used is dependent on the derived control. + * + * @see DevelControl::State + */ + SUB_STATE = BACKGROUND + 3 }; } // namespace Property diff --git a/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp b/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp index 48019fe..d3fcc56 100755 --- a/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp +++ b/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp @@ -18,8 +18,13 @@ // CLASS HEADER #include -// INTERNAL INCLUDES +// EXTERNAL INCLUDES #include +#include +#include +#include + +// INTERNAL INCLUDES #include #include #include @@ -34,11 +39,26 @@ namespace Toolkit namespace Internal { +namespace +{ + +BaseHandle Create() +{ + // empty handle as we cannot create control wrapper + return BaseHandle(); +} + +// Setup type-registry. +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ControlWrapper, Toolkit::Control, Create ) +DALI_TYPE_REGISTRATION_END() + +} + /* * Implementation. */ -Dali::Toolkit::ControlWrapper ControlWrapper::New( ControlWrapper* controlWrapper ) +Dali::Toolkit::ControlWrapper ControlWrapper::New( const std::string& typeName, ControlWrapper* controlWrapper ) { ControlWrapperPtr wrapper( controlWrapper ); @@ -49,6 +69,19 @@ Dali::Toolkit::ControlWrapper ControlWrapper::New( ControlWrapper* controlWrappe // This can only be done after the CustomActor connection has been made. wrapper->Initialize(); + // Different types of C# custom view registered themselves using type registry, + // but their type names are registered per type not per instance, so they still + // have the same wrong type name in native side when type registry queries the + // unique type name of each instance using typeid() because of the binding. + // Therefore, we have to link each instance with its correct type info if already + // pre-registered. + + TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( typeName ); + if(typeInfo) + { + Dali::DevelHandle::SetTypeInfo( handle, typeInfo ); + } + return handle; } diff --git a/dali-toolkit/devel-api/controls/control-wrapper-impl.h b/dali-toolkit/devel-api/controls/control-wrapper-impl.h index fa9173f..33905a5 100755 --- a/dali-toolkit/devel-api/controls/control-wrapper-impl.h +++ b/dali-toolkit/devel-api/controls/control-wrapper-impl.h @@ -64,9 +64,13 @@ public: /** * Create a new ControlWrapper. + * + * @param[in] typeName The name of the type that is registered with this control + * @param[in] controlWrapper The implementation of this control + * * @return A public handle to the newly allocated ControlWrapper. */ - static Dali::Toolkit::ControlWrapper New( ControlWrapper* controlWrapper ); + static Dali::Toolkit::ControlWrapper New( const std::string& typeName, ControlWrapper* controlWrapper ); public: // From CustomActorImpl diff --git a/dali-toolkit/devel-api/controls/control-wrapper.cpp b/dali-toolkit/devel-api/controls/control-wrapper.cpp index 7f8db27..0c6be01 100644 --- a/dali-toolkit/devel-api/controls/control-wrapper.cpp +++ b/dali-toolkit/devel-api/controls/control-wrapper.cpp @@ -31,9 +31,9 @@ namespace Toolkit // ControlWrapper /////////////////////////////////////////////////////////////////////////////////////////////////// -ControlWrapper ControlWrapper::New( Internal::ControlWrapper& implementation ) +ControlWrapper ControlWrapper::New( const std::string& typeName, Internal::ControlWrapper& implementation ) { - return Internal::ControlWrapper::New( &implementation ); + return Internal::ControlWrapper::New( typeName, &implementation ); } ControlWrapper::ControlWrapper() diff --git a/dali-toolkit/devel-api/controls/control-wrapper.h b/dali-toolkit/devel-api/controls/control-wrapper.h index a45c4b5..b50852b 100644 --- a/dali-toolkit/devel-api/controls/control-wrapper.h +++ b/dali-toolkit/devel-api/controls/control-wrapper.h @@ -45,9 +45,12 @@ public: /** * @brief Create a new instance of a ControlWrapper. * + * @param[in] typeName The name of the type that is registered with this control + * @param[in] implementation The implementation of this control + * * @return A handle to a new ControlWrapper. */ - static ControlWrapper New( Internal::ControlWrapper& implementation ); + static ControlWrapper New( const std::string& typeName, Internal::ControlWrapper& implementation ); /** * @brief Creates an empty ControlWrapper handle. diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h index 5201c08..31cf939 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h @@ -75,23 +75,114 @@ public: { enum { - POPUP_MAX_SIZE = PROPERTY_START_INDEX, ///< name "popupMaxSize", maximum size the Popup can be, type VECTOR2 - POPUP_MIN_SIZE, ///< name "popupMinSize", minimum size the Popup can be, type VECTOR2 - OPTION_MAX_SIZE, ///< name "optionMaxSize", maximum size an option can be, type VECTOR2 - OPTION_MIN_SIZE, ///< name "optionMinSize", minimum size an option can be, type VECTOR2 - OPTION_DIVIDER_SIZE, ///< name "optionDividerSize", size of the divider between options type VECTOR2 - POPUP_CLIPBOARD_BUTTON_ICON_IMAGE, ///< name "popupClipboardButtonImage", The image to use as the popup clipboard icon, type STRING - POPUP_CUT_BUTTON_ICON_IMAGE, ///< name "popupCutButtonImage", The image to use as the popup cut icon, type STRING - POPUP_COPY_BUTTON_ICON_IMAGE, ///< name "popupCopyButtonImage", The image to use as the popup copy icon, type STRING - POPUP_PASTE_BUTTON_ICON_IMAGE, ///< name "popupPasteButtonImage", The image to use as the popup paste icon, type STRING - POPUP_SELECT_BUTTON_ICON_IMAGE, ///< name "popupSelectButtonImage", The image to use as the popup select icon, type STRING - POPUP_SELECT_ALL_BUTTON_ICON_IMAGE, ///< name "popupSelectAllButtonImage", The image to use as the popup select all icon, type STRING - POPUP_DIVIDER_COLOR, ///< name "popupDividerColor", The color of the divider between options, type VECTOR4 - POPUP_ICON_COLOR, ///< name "popupIconColor", The color of the icons (if supplied), type VECTOR4 - POPUP_PRESSED_COLOR, ///< name "popupPressedColor", The color of the option when pressed, type VECTOR4 - POPUP_PRESSED_IMAGE, ///< name "popupPressedImage", The image to use for the option when pressed, type STRING - POPUP_FADE_IN_DURATION, ///< name "popupFadeInDuration", The duration of the fade-in animation, type FLOAT - POPUP_FADE_OUT_DURATION, ///< name "popupFadeOutDuration", The duration of the fade-out animation, type FLOAT + /** + * @brief The maximum size the Popup can be. + * @details Name "popupMaxSize", type Vector2. + */ + POPUP_MAX_SIZE = PROPERTY_START_INDEX, + + /** + * @brief The minimum size the Popup can be. + * @details Name "popupMinSize", type Vector2. + */ + POPUP_MIN_SIZE, + + /** + * @brief The maximum size an option can be. + * @details Name "optionMaxSize", type Vector2. + */ + OPTION_MAX_SIZE, + + /** + * @brief The minimum size an option can be. + * @details Name "optionMinSize", type Vector2. + */ + OPTION_MIN_SIZE, + + /** + * @brief The size of the divider between options. + * @details Name "optionDividerSize", type Vector2. + */ + OPTION_DIVIDER_SIZE, + + /** + * @brief The image to use as the popup clipboard icon. + * @details Name "popupClipboardButtonImage", type string. + */ + POPUP_CLIPBOARD_BUTTON_ICON_IMAGE, + + /** + * @brief The image to use as the popup cut icon. + * @details Name "popupCutButtonImage", type string. + */ + POPUP_CUT_BUTTON_ICON_IMAGE, + + /** + * @brief The image to use as the popup copy icon. + * @details Name "popupCopyButtonImage", type string. + */ + POPUP_COPY_BUTTON_ICON_IMAGE, + + /** + * @brief The image to use as the popup paste icon. + * @details Name "popupPasteButtonImage", type string. + */ + POPUP_PASTE_BUTTON_ICON_IMAGE, + + /** + * @brief The image to use as the popup select icon. + * @details Name "popupSelectButtonImage", type string. + */ + POPUP_SELECT_BUTTON_ICON_IMAGE, + + /** + * @brief The image to use as the popup select all icon. + * @details Name "popupSelectAllButtonImage", type string. + */ + POPUP_SELECT_ALL_BUTTON_ICON_IMAGE, + + /** + * @brief The color of the divider between options. + * @details Name "popupDividerColor", type Vector4. + */ + POPUP_DIVIDER_COLOR, + + /** + * @brief The color of the icons (if supplied). + * @details Name "popupIconColor", type Vector4. + */ + POPUP_ICON_COLOR, + + /** + * @brief The color of the option when pressed. + * @details Name "popupPressedColor", type Vector4. + */ + POPUP_PRESSED_COLOR, + + /** + * @brief The image to use for the option when pressed. + * @details Name "popupPressedImage", type string. + */ + POPUP_PRESSED_IMAGE, + + /** + * @brief The duration of the fade-in animation. + * @details Name "popupFadeInDuration", type float. + */ + POPUP_FADE_IN_DURATION, + + /** + * @brief The duration of the fade-out animation. + * @details Name "popupFadeOutDuration", type float. + */ + POPUP_FADE_OUT_DURATION, + + /** + * @brief The popup background can have a separate border with a different color. + * @details Name "backgroundBorder", type Property::Map. + * @note Optional. + */ + BACKGROUND_BORDER }; }; diff --git a/dali-toolkit/devel-api/visuals/visual-properties-devel.h b/dali-toolkit/devel-api/visuals/visual-properties-devel.h index 9c9a628..b70d254 100644 --- a/dali-toolkit/devel-api/visuals/visual-properties-devel.h +++ b/dali-toolkit/devel-api/visuals/visual-properties-devel.h @@ -76,11 +76,19 @@ enum Type /** * @brief Mix color is a blend color for any visual. - * @details Name "mixColor", type Property::VECTOR4 + * @details Name "mixColor", type Property::VECTOR3 or Property::VECTOR4 * * @note Optional */ MIX_COLOR = SHADER + 3, + + /** + * @brief Opacity is the alpha component of the mixColor, above. + * @details Name "opacity", type Property::FLOAT + * + * @note Optional + */ + OPACITY = SHADER + 4 }; } //namespace Property diff --git a/dali-toolkit/internal/builder/builder-impl.cpp b/dali-toolkit/internal/builder/builder-impl.cpp index a7fabdf..ac5ea3e 100644 --- a/dali-toolkit/internal/builder/builder-impl.cpp +++ b/dali-toolkit/internal/builder/builder-impl.cpp @@ -22,29 +22,29 @@ #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include +#include #include +#include #include +#include // INTERNAL INCLUDES #include #include -#include -#include #include +#include +#include +#include #include #include #include -#include - namespace Dali { @@ -56,9 +56,12 @@ namespace Internal class Replacement; extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder ); + extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder); + extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder); + #if defined(DEBUG_ENABLED) Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT"); #endif @@ -68,14 +71,20 @@ namespace #define TOKEN_STRING(x) #x -const std::string KEYNAME_STYLES = "styles"; -const std::string KEYNAME_TYPE = "type"; -const std::string KEYNAME_ACTORS = "actors"; -const std::string KEYNAME_SIGNALS = "signals"; -const std::string KEYNAME_NAME = "name"; -const std::string KEYNAME_TEMPLATES = "templates"; -const std::string KEYNAME_INCLUDES = "includes"; -const std::string KEYNAME_MAPPINGS = "mappings"; +const std::string KEYNAME_ACTORS = "actors"; +const std::string KEYNAME_ENTRY_TRANSITION = "entryTransition"; +const std::string KEYNAME_EXIT_TRANSITION = "exitTransition"; +const std::string KEYNAME_INCLUDES = "includes"; +const std::string KEYNAME_INHERIT = "inherit"; +const std::string KEYNAME_MAPPINGS = "mappings"; +const std::string KEYNAME_NAME = "name"; +const std::string KEYNAME_SIGNALS = "signals"; +const std::string KEYNAME_STATES = "states"; +const std::string KEYNAME_STYLES = "styles"; +const std::string KEYNAME_TEMPLATES = "templates"; +const std::string KEYNAME_TRANSITIONS = "transitions"; +const std::string KEYNAME_TYPE = "type"; +const std::string KEYNAME_VISUALS = "visuals"; const std::string PROPERTIES = "properties"; const std::string ANIMATABLE_PROPERTIES = "animatableProperties"; @@ -121,7 +130,12 @@ void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, { styleList.push_back( &(*node) ); - if( OptionalChild subStyle = IsChild( *node, KEYNAME_STYLES ) ) + OptionalChild subStyle = IsChild( *node, KEYNAME_INHERIT ); + if( ! subStyle ) + { + subStyle = IsChild( *node, KEYNAME_STYLES ); + } + if( subStyle ) { CollectAllStyles( stylesCollection, *subStyle, styleList ); } @@ -134,379 +148,256 @@ void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, } // namespace anon -/* - * Sets the handle properties found in the tree node - */ -void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ) + +Builder::Builder() +: mSlotDelegate( this ) { - if( handle ) - { + mParser = Dali::Toolkit::JsonParser::New(); - for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) - { - const TreeNode::KeyNodePair& keyChild = *iter; + Property::Map defaultDirs; + defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ] = DALI_IMAGE_DIR; + defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ] = DALI_SOUND_DIR; + defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR; + defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR; - std::string key( keyChild.first ); + AddConstants( defaultDirs ); +} - // ignore special fields; type,actors,signals,styles - if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES || key == KEYNAME_MAPPINGS ) - { - continue; - } +void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) +{ + // parser to get constants and includes only + Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); + + if( !parser.Parse( data ) ) + { + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + parser.GetErrorLineNumber(), + parser.GetErrorColumn(), + parser.GetErrorDescription().c_str() ); - Handle propertyObject( handle ); + DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + } + else + { + // load constant map (allows the user to override the constants in the json after loading) + LoadConstants( *parser.GetRoot(), mReplacementMap ); - Dali::Property::Index index = propertyObject.GetPropertyIndex( key ); + // merge includes + if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) ) + { + Replacement replacer( mReplacementMap ); - if( Property::INVALID_INDEX != index ) + for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) { - Property::Type type = propertyObject.GetPropertyType(index); - Property::Value value; - bool mapped = false; + OptionalString filename = replacer.IsString( (*iter).second ); - // if node.value is a mapping, get the property value from the "mappings" table - if( keyChild.second.GetType() == TreeNode::STRING ) - { - std::string mappingKey; - if( GetMappingKey(keyChild.second.GetString(), mappingKey) ) - { - OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS ); - mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value ); - } - } - if( ! mapped ) - { - mapped = DeterminePropertyFromNode( keyChild.second, type, value, constant ); - if( ! mapped ) - { - // Just determine the property from the node and if it's valid, let the property object handle it - DeterminePropertyFromNode( keyChild.second, value, constant ); - mapped = ( value.GetType() != Property::NONE ); - } - } - if( mapped ) + if( filename ) { - DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() ); - - propertyObject.SetProperty( index, value ); +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); +#endif + LoadFromString( GetFileContents(*filename) ); } } - else - { - DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str()); - } + } - // Add custom properties - SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE); - SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE); + if( !mParser.Parse( data ) ) + { + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + mParser.GetErrorLineNumber(), + mParser.GetErrorColumn(), + mParser.GetErrorDescription().c_str() ); - } // for property nodes - } - else - { - DALI_SCRIPT_WARNING("Style applied to empty handle\n"); + DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + } } + + DUMP_PARSE_TREE(parser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet. + DUMP_TEST_MAPPINGS(parser); + + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON"); } -void Builder::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, - const std::string& childName, Property::AccessMode accessMode ) +void Builder::AddConstants( const Property::Map& map ) { - // Add custom properties - if( OptionalChild customPropertiesChild = IsChild(node, childName) ) - { - const TreeNode& customPropertiesNode = *customPropertiesChild; - const TreeConstIter endIter = customPropertiesNode.CEnd(); - for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter ) - { - const TreeNode::KeyNodePair& keyChild = *iter; - std::string key( keyChild.first ); + mReplacementMap.Merge( map ); +} - Property::Value value; - DeterminePropertyFromNode( keyChild.second, value, constant ); - // Register/Set property. - handle.RegisterProperty( key, value, accessMode ); - } - } +void Builder::AddConstant( const std::string& key, const Property::Value& value ) +{ + mReplacementMap[key] = value; } -// Set properties from node on handle. -void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +const Property::Map& Builder::GetConstants() const { - if( Actor actor = Actor::DownCast(handle) ) - { - SetProperties( node, actor, constant ); + return mReplacementMap; +} - if( actor ) - { - // add signals - SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); - SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); - } +const Property::Value& Builder::GetConstant( const std::string& key ) const +{ + Property::Value* match = mReplacementMap.Find( key ); + if( match ) + { + return (*match); } else { - SetProperties( node, handle, constant ); + static Property::Value invalid; + return invalid; } } -// Appling by style helper -// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node -void Builder::ApplyStylesByActor( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) { - if( Dali::Actor actor = Dali::Actor::DownCast( handle ) ) - { - if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) ) - { - // in a style the actor subtree properties referenced by actor name - for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter ) - { - Dali::Actor foundActor; - - if( (*iter).first ) - { - foundActor = actor.FindChildByName( (*iter).first ); - } - - if( !foundActor ) - { - // debug log cannot find searched for actor -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first); -#endif - } - else - { -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); -#endif - ApplyProperties( root, (*iter).second, foundActor, constant ); - } - } - } - } + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, sourceActor); } +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) +{ + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); +} -void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) { - OptionalChild styles = IsChild(root, KEYNAME_STYLES); - OptionalChild style = IsChild(node, KEYNAME_STYLES); + Replacement replacement( mReplacementMap ); - if( styles && style ) - { - TreeNodeList additionalStyles; + return CreateAnimation( animationName, replacement, sourceActor ); +} - CollectAllStyles( *styles, *style, additionalStyles ); +Animation Builder::CreateAnimation( const std::string& animationName ) +{ + Replacement replacement( mReplacementMap ); -#if defined(DEBUG_ENABLED) - for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter) - { - if( OptionalString styleName = IsString( (*iter).second ) ) - { - DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); - } - } -#endif + return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); +} - // a style may have other styles, which has other styles etc so we apply in reverse by convention. - for(TreeNodeList::reverse_iterator iter = additionalStyles.rbegin(); iter != additionalStyles.rend(); ++iter) - { - ApplyProperties( root, *(*iter), handle, constant ); +BaseHandle Builder::Create( const std::string& templateName ) +{ + Replacement replacement( mReplacementMap ); + return Create( templateName, replacement ); +} - ApplyStylesByActor( root, *(*iter), handle, constant ); - } - } +BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) +{ + Replacement replacement( map, mReplacementMap ); + return Create( templateName, replacement ); +} + +BaseHandle Builder::CreateFromJson( const std::string& json ) +{ + BaseHandle ret; - // applying given node last - ApplyProperties( root, node, handle, constant ); + // merge in new template, hoping no one else has one named '@temp@' + std::string newTemplate = + std::string("{\"templates\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - ApplyStylesByActor( root, node, handle, constant ); + if( mParser.Parse(newTemplate) ) + { + Replacement replacement( mReplacementMap ); + ret = Create( "@temp@", replacement ); + } + return ret; } - -/* - * Create a dali type from a node. - * If parent given and an actor type was created then add it to the parent and - * recursively add nodes children. - */ -BaseHandle Builder::DoCreate( const TreeNode& root, const TreeNode& node, - Actor parent, const Replacement& replacements ) +bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) { - BaseHandle baseHandle; - TypeInfo typeInfo; - const TreeNode* templateNode = NULL; - - if( OptionalString typeName = IsString(node, KEYNAME_TYPE) ) - { - typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName ); + bool ret = false; - if( !typeInfo ) - { - // a template name is also allowed inplace of the type name - OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES); - - if( templates ) - { - if( OptionalChild isTemplate = IsChild( *templates, *typeName ) ) - { - templateNode = &(*isTemplate); - - if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) - { - typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); - } - } - } - } - } + // merge new style, hoping no one else has one named '@temp@' + std::string newStyle = + std::string("{\"styles\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - if(!typeInfo) + if( mParser.Parse(newStyle) ) { - DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName()); + Replacement replacement( mReplacementMap ); + ret = ApplyStyle( "@temp@", handle, replacement ); } - else - { - baseHandle = typeInfo.CreateInstance(); - Handle handle = Handle::DownCast(baseHandle); - Actor actor = Actor::DownCast(handle); - - if(handle) - { - - DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str()); - -#if defined(DEBUG_ENABLED) - if(handle) - { - DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr()); - DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount()); - } - - if(actor) - { - DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId()); - } - - Toolkit::Control control = Toolkit::Control::DownCast(handle); - if(control) - { - DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId()); - } -#endif // DEBUG_ENABLED - if( templateNode ) - { - ApplyProperties( root, *templateNode, handle, replacements ); + return ret; +} - if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) - { - for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) - { - DoCreate( root, (*iter).second, actor, replacements ); - } - } - } +bool Builder::ApplyStyle( const std::string& styleName, Handle& handle ) +{ + Replacement replacer( mReplacementMap ); + return ApplyStyle( styleName, handle, replacer ); +} - if( actor ) - { - // add children of all the styles - if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) ) - { - for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) - { - DoCreate( root, (*iter).second, actor, replacements ); - } - } +bool Builder::LookupStyleName( const std::string& styleName ) +{ + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - // apply style on top as they need the children to exist - ApplyAllStyleProperties( root, node, actor, replacements ); + OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); + OptionalChild style = IsChildIgnoreCase( *styles, styleName ); - // then add to parent - if( parent ) - { - parent.Add( actor ); - } - } - else - { - ApplyProperties( root, node, handle, replacements ); - } - } - else - { - DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str()); - } + if( styles && style ) + { + return true; } - - return baseHandle; + return false; } -void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) +const StylePtr Builder::GetStyle( const std::string& styleName ) { - const Stage& stage = Stage::GetCurrent(); - Layer root = stage.GetRootLayer(); + const StylePtr* style = mStyles.FindCaseInsensitiveC( styleName ); - if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) ) + if( style==NULL ) { - Actor actor = root.FindChildByName(*s); - if(actor) - { - task.SetSourceActor( actor ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() ); - } + return StylePtr(NULL); } - - if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) ) + else { - CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) ); - if(actor) - { - task.SetCameraActor( actor ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() ); - } + return *style; } +} - if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) ) - { - FrameBufferImage fb = GetFrameBufferImage( *s, constant ); - if(fb) - { - task.SetTargetFrameBuffer( fb ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); - } - } +void Builder::AddActors( Actor toActor ) +{ + // 'stage' is the default/by convention section to add from + AddActors( "stage", toActor ); +} - if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) ) +void Builder::AddActors( const std::string §ionName, Actor toActor ) +{ + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + + Property::Map overrideMap; + Replacement replacements(overrideMap, mReplacementMap); + + OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); + + if( add ) { - if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s) - { - task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ); - } - else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s) + for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) { - task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION ); + // empty actor adds directly to the stage + BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements ); + Actor actor = Actor::DownCast(baseHandle); + if(actor) + { + toActor.Add( actor ); + } } - else + + // if were adding the 'stage' section then also check for a render task called stage + // to add automatically + if( "stage" == sectionName ) { - DALI_SCRIPT_WARNING("todo"); + if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") ) + { + if( OptionalChild tasks = IsChild(*renderTasks, "stage") ) + { + CreateRenderTask( "stage" ); + } + } } } - - // other setup is via the property system - SetProperties( node, task, constant ); } void Builder::CreateRenderTask( const std::string &name ) @@ -741,6 +632,7 @@ PathConstrainer Builder::GetPathConstrainer( const std::string& name ) return ret; } + bool Builder::IsPathConstrainer( const std::string& name ) { size_t count( mPathConstrainerLut.size() ); @@ -877,60 +769,67 @@ void Builder::EmitQuitSignal() mQuitSignal.Emit(); } -void Builder::AddActors( Actor toActor ) +Builder::~Builder() { - // 'stage' is the default/by convention section to add from - AddActors( "stage", toActor ); } -void Builder::AddActors( const std::string §ionName, Actor toActor ) +void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) { - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - - Property::Map overrideMap; - Replacement replacements(overrideMap, mReplacementMap); - - OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); + Replacement replacer(intoMap); - if( add ) + if( OptionalChild constants = IsChild(root, "constants") ) { - for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) - { - // empty actor adds directly to the stage - BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements ); - Actor actor = Actor::DownCast(baseHandle); - if(actor) - { - toActor.Add( actor ); - } - } - - // if were adding the 'stage' section then also check for a render task called stage - // to add automatically - if( "stage" == sectionName ) + for(TreeNode::ConstIterator iter = (*constants).CBegin(); + iter != (*constants).CEnd(); ++iter) { - if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") ) + Dali::Property::Value property; + if( (*iter).second.GetName() ) { - if( OptionalChild tasks = IsChild(*renderTasks, "stage") ) - { - CreateRenderTask( "stage" ); - } +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName()); +#endif + DeterminePropertyFromNode( (*iter).second, property, replacer ); + intoMap[ (*iter).second.GetName() ] = property; } } } -} - -Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ) -{ - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - - Animation anim; - if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") ) +#if defined(DEBUG_ENABLED) + Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" ); + if( iter && iter->GetType() == Property::STRING ) { - if( OptionalChild animation = IsChild(*animations, animationName) ) + std::string logLevel( iter->Get< std::string >() ); + if( logLevel == "NoLogging" ) { - anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this ); + gFilterScript->SetLogLevel( Integration::Log::NoLogging ); + } + else if( logLevel == "Concise" ) + { + gFilterScript->SetLogLevel( Integration::Log::Concise ); + } + else if( logLevel == "General" ) + { + gFilterScript->SetLogLevel( Integration::Log::General ); + } + else if( logLevel == "Verbose" ) + { + gFilterScript->SetLogLevel( Integration::Log::Verbose ); + } + } +#endif +} + +Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ) +{ + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + + Animation anim; + + if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") ) + { + if( OptionalChild animation = IsChild(*animations, animationName) ) + { + anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this ); } else { @@ -945,412 +844,737 @@ Animation Builder::CreateAnimation( const std::string& animationName, const Repl return anim; } -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) +BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant ) { - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, sourceActor); -} + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) -{ - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); -} + BaseHandle baseHandle; -Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) -{ - Replacement replacement( mReplacementMap ); + OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES); - return CreateAnimation( animationName, replacement, sourceActor ); -} + if( !templates ) + { + DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n"); + } + else + { + OptionalChild childTemplate = IsChild(*templates, templateName); + if(!childTemplate) + { + DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str()); + } + else + { + OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) ); -Animation Builder::CreateAnimation( const std::string& animationName ) -{ - Replacement replacement( mReplacementMap ); + if(!type) + { + DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str()); + } + else + { + baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant ); + } + } + } - return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); + return baseHandle; } -bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child ) +/* + * Create a dali type from a node. + * If parent given and an actor type was created then add it to the parent and + * recursively add nodes children. + */ +BaseHandle Builder::DoCreate( const TreeNode& root, const TreeNode& node, + Actor parent, const Replacement& replacements ) { - bool result = false; + BaseHandle baseHandle; + TypeInfo typeInfo; + const TreeNode* templateNode = NULL; - switch( child.GetType() ) + if( OptionalString typeName = IsString(node, KEYNAME_TYPE) ) { - case Property::STRING: + typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName ); + + if( !typeInfo ) { - std::string value; - if( child.Get( value ) ) + // a template name is also allowed inplace of the type name + OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES); + + if( templates ) { - std::string key; - if( GetMappingKey( value, key ) ) + if( OptionalChild isTemplate = IsChild( *templates, *typeName ) ) { - // Check key for cycles: - result=true; - for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter ) - { - if( key.compare(*iter) == 0 ) - { - // key is already in stack; stop. - DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str()); - child = Property::Value(""); - result=false; - break; - } - } + templateNode = &(*isTemplate); - if( result ) + if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) { - // The following call will overwrite the child with the value - // from the mapping. - RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child ); - result = true; + typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); } } } - break; } + } - case Property::MAP: + if(!typeInfo) + { + DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName()); + } + else + { + baseHandle = typeInfo.CreateInstance(); + Handle handle = Handle::DownCast(baseHandle); + Actor actor = Actor::DownCast(handle); + + if(handle) { - Property::Map* map = child.GetMap(); - if( map ) + + DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str()); + +#if defined(DEBUG_ENABLED) + if(handle) { - for( Property::Map::SizeType i=0; i < map->Count(); ++i ) - { - Property::Value& child = map->GetValue(i); - ConvertChildValue(mappingRoot, keyStack, child); - } + DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr()); + DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount()); } - break; - } - case Property::ARRAY: - { - Property::Array* array = child.GetArray(); - if( array ) + if(actor) { - for( Property::Array::SizeType i=0; i < array->Count(); ++i ) - { - Property::Value& child = array->GetElementAt(i); - ConvertChildValue(mappingRoot, keyStack, child); - } + DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId()); } - break; - } - - default: - // Ignore other types. - break; - } - return result; -} + Toolkit::Control control = Toolkit::Control::DownCast(handle); + if(control) + { + DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId()); + } +#endif // DEBUG_ENABLED -bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ) -{ - Replacement replacer( mReplacementMap ); - bool result = false; + if( templateNode ) + { + ApplyProperties( root, *templateNode, handle, replacements ); - keyStack.push_back( theKey ); + if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) + { + for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) + { + DoCreate( root, (*iter).second, actor, replacements ); + } + } + } - for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter ) - { - std::string aKey( (*iter).first ); - if( aKey.compare( theKey ) == 0 ) - { - if( propertyType == Property::NONE ) + if( actor ) { - DeterminePropertyFromNode( (*iter).second, value, replacer ); - result = true; + // add children of all the styles + if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) ) + { + for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) + { + DoCreate( root, (*iter).second, actor, replacements ); + } + } + + // apply style on top as they need the children to exist + ApplyAllStyleProperties( root, node, actor, replacements ); + + // then add to parent + if( parent ) + { + parent.Add( actor ); + } } else { - result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer ); - } - - if( result ) - { - ConvertChildValue(mappingRoot, keyStack, value); + ApplyProperties( root, node, handle, replacements ); } - break; + } + else + { + DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str()); } } - keyStack.pop_back(); - - return result; -} - -bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ) -{ - KeyStack keyStack; - return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value ); + return baseHandle; } - -void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) +void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) { - // parser to get constants and includes only - Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); + const Stage& stage = Stage::GetCurrent(); + Layer root = stage.GetRootLayer(); - if( !parser.Parse( data ) ) + if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) ) { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - parser.GetErrorLineNumber(), - parser.GetErrorColumn(), - parser.GetErrorDescription().c_str() ); - - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + Actor actor = root.FindChildByName(*s); + if(actor) + { + task.SetSourceActor( actor ); + } + else + { + DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() ); + } } - else - { - // load constant map (allows the user to override the constants in the json after loading) - LoadConstants( *parser.GetRoot(), mReplacementMap ); - // merge includes - if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) ) + if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) ) + { + CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) ); + if(actor) { - Replacement replacer( mReplacementMap ); - - for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) - { - OptionalString filename = replacer.IsString( (*iter).second ); - - if( filename ) - { -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); -#endif - LoadFromString( GetFileContents(*filename) ); - } - } + task.SetCameraActor( actor ); } - - if( !mParser.Parse( data ) ) + else { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - mParser.GetErrorLineNumber(), - mParser.GetErrorColumn(), - mParser.GetErrorDescription().c_str() ); + DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() ); + } + } - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) ) + { + FrameBufferImage fb = GetFrameBufferImage( *s, constant ); + if(fb) + { + task.SetTargetFrameBuffer( fb ); + } + else + { + DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); } } - DUMP_PARSE_TREE(parser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet. - DUMP_TEST_MAPPINGS(parser); + if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) ) + { + if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s) + { + task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ); + } + else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s) + { + task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION ); + } + else + { + DALI_SCRIPT_WARNING("todo"); + } + } - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON"); + // other setup is via the property system + SetProperties( node, task, constant ); } -void Builder::AddConstants( const Property::Map& map ) +bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement ) { - mReplacementMap.Merge( map ); -} + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); -void Builder::AddConstant( const std::string& key, const Property::Value& value ) -{ - mReplacementMap[key] = value; -} + OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); -const Property::Map& Builder::GetConstants() const -{ - return mReplacementMap; -} + std::string styleNameLower(styleName); + OptionalChild style = IsChildIgnoreCase( *styles, styleNameLower ); -const Property::Value& Builder::GetConstant( const std::string& key ) const -{ - Property::Value* match = mReplacementMap.Find( key ); - if( match ) + if( styles && style ) { - return (*match); + ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement ); + return true; } else { - static Property::Value invalid; - return invalid; + return false; } } -void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) +void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) { - Replacement replacer(intoMap); + const char* styleName = node.GetName(); - if( OptionalChild constants = IsChild(root, "constants") ) + StylePtr style = Style::New(); + + StylePtr* matchedStyle = NULL; + if( styleName ) { - for(TreeNode::ConstIterator iter = (*constants).CBegin(); - iter != (*constants).CEnd(); ++iter) + matchedStyle = mStyles.FindCaseInsensitive( styleName ); + if( ! matchedStyle ) { - Dali::Property::Value property; - if( (*iter).second.GetName() ) + OptionalChild styleNodes = IsChild(root, KEYNAME_STYLES); + OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT); + if( !inheritFromNode ) + { + inheritFromNode = IsChild( node, KEYNAME_STYLES ); + } + + if( styleNodes ) { + if( inheritFromNode ) + { + TreeNodeList additionalStyleNodes; + + CollectAllStyles( *styleNodes, *inheritFromNode, additionalStyleNodes ); + #if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName()); + for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter) + { + if( OptionalString styleName = IsString( (*iter).second ) ) + { + DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); + } + } #endif - DeterminePropertyFromNode( (*iter).second, property, replacer ); - intoMap[ (*iter).second.GetName() ] = property; + + // a style may have other styles, which has other styles etc so we apply in reverse by convention. + for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter) + { + RecordStyle( style, *(*iter), handle, constant ); + ApplySignals( root, *(*iter), handle ); + ApplyStylesByActor( root, *(*iter), handle, constant ); + } + } + + RecordStyle( style, node, handle, constant ); + mStyles.Add( styleName, style ); // shallow copy + matchedStyle = &style; } } } -#if defined(DEBUG_ENABLED) - Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" ); - if( iter && iter->GetType() == Property::STRING ) + if( matchedStyle ) { - std::string logLevel( iter->Get< std::string >() ); - if( logLevel == "NoLogging" ) + StylePtr style( *matchedStyle ); + style->ApplyVisualsAndPropertiesRecursively( handle ); // (recurses through states) + } + else // If there were no styles, instead set properties + { + SetProperties( node, handle, constant ); + } + ApplySignals( root, node, handle ); + ApplyStylesByActor( root, node, handle, constant ); +} + +void Builder::RecordStyle( StylePtr style, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& replacements ) +{ + // With repeated calls, accumulate inherited states, visuals and properties + // but override any with same name + + for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) + { + const TreeNode::KeyNodePair& keyValue = *iter; + std::string key( keyValue.first ); + if( key == KEYNAME_STATES ) { - gFilterScript->SetLogLevel( Integration::Log::NoLogging ); + const TreeNode& states = keyValue.second; + if( states.GetType() != TreeNode::OBJECT ) + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str() ); + continue; + } + + for( TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter ) + { + const TreeNode& stateNode = (*iter).second; + const char* stateName = stateNode.GetName(); + if( stateNode.GetType() != TreeNode::OBJECT ) + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", stateName ); + continue; + } + + StylePtr* stylePtr = style->subStates.FindCaseInsensitive( stateName ); + if( stylePtr ) + { + StylePtr style(*stylePtr); + RecordStyle( style, stateNode, handle, replacements ); + } + else + { + StylePtr subState = Style::New(); + RecordStyle( subState, stateNode, handle, replacements ); + style->subStates.Add( stateName, subState ); + } + } } - else if( logLevel == "Concise" ) + else if( key == KEYNAME_VISUALS ) { - gFilterScript->SetLogLevel( Integration::Log::Concise ); + for( TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter ) + { + // Each key in this table should be a property name matching a visual. + const TreeNode::KeyNodePair& visual = *iter; + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( visual.second, Property::MAP, property, replacements ) ) + { + Property::Map* mapPtr = style->visuals.FindCaseInsensitive( visual.first ); + if( mapPtr ) + { + // Override existing visuals + mapPtr->Clear(); + mapPtr->Merge(*property.GetMap()); + } + else + { + style->visuals.Add(visual.first, *property.GetMap()); + } + } + } } - else if( logLevel == "General" ) + else if( key == KEYNAME_ENTRY_TRANSITION ) { - gFilterScript->SetLogLevel( Integration::Log::General ); + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) ) + { + style->entryTransition = Toolkit::TransitionData::New( *property.GetMap() ); + } } - else if( logLevel == "Verbose" ) + else if( key == KEYNAME_EXIT_TRANSITION ) { - gFilterScript->SetLogLevel( Integration::Log::Verbose ); + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) ) + { + style->exitTransition = Toolkit::TransitionData::New( *property.GetMap() ); + } + } + else if( key == KEYNAME_TRANSITIONS ) + { + //@todo add new transitions to style.transitions + // override existing transitions. A transition matches on target & property name + const TreeNode& node = keyValue.second; + if( node.GetType() == TreeNode::ARRAY ) + { + Dali::Property::Value property(Property::ARRAY); + if( DeterminePropertyFromNode( node, Property::ARRAY, property, replacements ) ) + { + style->transitions = *property.GetArray(); + } + } + else if( node.GetType() == TreeNode::OBJECT ) + { + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( node, Property::MAP, property, replacements ) ) + { + Property::Array propertyArray; + propertyArray.Add( property ); + style->transitions = propertyArray; + } + } + else + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON array or object\n", key.c_str() ); + } + } + else if( key == KEYNAME_TYPE || + key == KEYNAME_ACTORS || + key == KEYNAME_SIGNALS || + key == KEYNAME_STYLES || + key == KEYNAME_MAPPINGS || + key == KEYNAME_INHERIT ) + { + continue; + } + else // It's a property + { + Property::Index index; + Property::Value value; + if( MapToTargetProperty( handle, key, keyValue.second, replacements, index, value ) ) + { + Property::Value* existingValuePtr = style->properties.Find( index ); + if( existingValuePtr != NULL ) + { + *existingValuePtr = value; // Overwrite existing property. + } + else + { + style->properties.Add( index, value ); + } + } } } -#endif +} +// Set properties from node on handle. +void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) +{ + SetProperties( node, handle, constant ); + ApplySignals( root, node, handle ); } -bool Builder::ApplyStyle( const std::string& styleName, Handle& handle ) +void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle ) { - Replacement replacer( mReplacementMap ); - return ApplyStyle( styleName, handle, replacer ); + Actor actor = Actor::DownCast(handle); + if( actor ) + { + // add signals + SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + } } -bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement ) + +// Appling by style helper +// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node +void Builder::ApplyStylesByActor( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) { - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + if( Dali::Actor actor = Dali::Actor::DownCast( handle ) ) + { + if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) ) + { + // in a style the actor subtree properties referenced by actor name + for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter ) + { + Dali::Actor foundActor; - OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); + if( (*iter).first ) + { + foundActor = actor.FindChildByName( (*iter).first ); + } - std::string styleNameLower(styleName); - OptionalChild style = IsChildIgnoreCase( *styles, styleNameLower ); + if( !foundActor ) + { + DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first); + } + else + { + DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); + ApplyProperties( root, (*iter).second, foundActor, constant ); + } + } + } + } +} - if( styles && style ) +/* + * Sets the handle properties found in the tree node + */ +void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ) +{ + if( handle ) { - ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement ); - return true; + for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) + { + const TreeNode::KeyNodePair& keyChild = *iter; + + std::string key( keyChild.first ); + + // ignore special fields; + if( key == KEYNAME_TYPE || + key == KEYNAME_ACTORS || + key == KEYNAME_SIGNALS || + key == KEYNAME_STYLES || + key == KEYNAME_MAPPINGS || + key == KEYNAME_INHERIT || + key == KEYNAME_STATES || + key == KEYNAME_VISUALS || + key == KEYNAME_ENTRY_TRANSITION || + key == KEYNAME_EXIT_TRANSITION || + key == KEYNAME_TRANSITIONS ) + { + continue; + } + + Property::Index index; + Property::Value value; + + bool mapped = MapToTargetProperty( handle, key, keyChild.second, constant, index, value ); + if( mapped ) + { + DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() ); + + handle.SetProperty( index, value ); + } + + // Add custom properties + SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE); + SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE); + + } // for property nodes } else { - return false; + DALI_SCRIPT_WARNING("Style applied to empty handle\n"); } } -BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) +bool Builder::MapToTargetProperty( + Handle& propertyObject, + const std::string& key, + const TreeNode& node, + const Replacement& constant, + Property::Index& index, + Property::Value& value ) { - Replacement replacement( map, mReplacementMap ); - return Create( templateName, replacement ); + bool mapped = false; + + index = propertyObject.GetPropertyIndex( key ); + if( Property::INVALID_INDEX != index ) + { + Property::Type type = propertyObject.GetPropertyType(index); + + // if node.value is a mapping, get the property value from the "mappings" table + if( node.GetType() == TreeNode::STRING ) + { + std::string mappingKey; + if( GetMappingKey( node.GetString(), mappingKey) ) + { + OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS ); + mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value ); + } + } + if( ! mapped ) + { + mapped = DeterminePropertyFromNode( node, type, value, constant ); + if( ! mapped ) + { + // Just determine the property from the node and if it's valid, let the property object handle it + DeterminePropertyFromNode( node, value, constant ); + mapped = ( value.GetType() != Property::NONE ); + } + } + } + else + { + DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str()); + } + return mapped; } -BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant ) +bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ) { - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + KeyStack keyStack; + return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value ); +} - BaseHandle baseHandle; +bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ) +{ + Replacement replacer( mReplacementMap ); + bool result = false; - OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES); + keyStack.push_back( theKey ); - if( !templates ) - { - DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n"); - } - else + for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter ) { - OptionalChild childTemplate = IsChild(*templates, templateName); - if(!childTemplate) - { - DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str()); - } - else + std::string aKey( (*iter).first ); + if( aKey.compare( theKey ) == 0 ) { - OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) ); - - if(!type) + if( propertyType == Property::NONE ) { - DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str()); + DeterminePropertyFromNode( (*iter).second, value, replacer ); + result = true; } else { - baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant ); + result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer ); + } + + if( result ) + { + ConvertChildValue(mappingRoot, keyStack, value); } + break; } } + keyStack.pop_back(); - return baseHandle; + return result; } -BaseHandle Builder::CreateFromJson( const std::string& json ) +bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child ) { - BaseHandle ret; - - // merge in new template, hoping no one else has one named '@temp@' - std::string newTemplate = - std::string("{\"templates\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + bool result = false; - if( mParser.Parse(newTemplate) ) + switch( child.GetType() ) { - Replacement replacement( mReplacementMap ); - ret = Create( "@temp@", replacement ); - } + case Property::STRING: + { + std::string value; + if( child.Get( value ) ) + { + std::string key; + if( GetMappingKey( value, key ) ) + { + // Check key for cycles: + result=true; + for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter ) + { + if( key.compare(*iter) == 0 ) + { + // key is already in stack; stop. + DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str()); + child = Property::Value(""); + result=false; + break; + } + } - return ret; -} + if( result ) + { + // The following call will overwrite the child with the value + // from the mapping. + RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child ); + result = true; + } + } + } + break; + } -bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) -{ - bool ret = false; + case Property::MAP: + { + Property::Map* map = child.GetMap(); + if( map ) + { + for( Property::Map::SizeType i=0; i < map->Count(); ++i ) + { + Property::Value& child = map->GetValue(i); + ConvertChildValue(mappingRoot, keyStack, child); + } + } + break; + } - // merge new style, hoping no one else has one named '@temp@' - std::string newStyle = - std::string("{\"styles\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + case Property::ARRAY: + { + Property::Array* array = child.GetArray(); + if( array ) + { + for( Property::Array::SizeType i=0; i < array->Count(); ++i ) + { + Property::Value& child = array->GetElementAt(i); + ConvertChildValue(mappingRoot, keyStack, child); + } + } + break; + } - if( mParser.Parse(newStyle) ) - { - Replacement replacement( mReplacementMap ); - ret = ApplyStyle( "@temp@", handle, replacement ); + default: + // Ignore other types. + break; } - return ret; -} - - -BaseHandle Builder::Create( const std::string& templateName ) -{ - Replacement replacement( mReplacementMap ); - return Create( templateName, replacement ); + return result; } -Builder::Builder() -: mSlotDelegate( this ) +void Builder::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, + const std::string& childName, Property::AccessMode accessMode ) { - mParser = Dali::Toolkit::JsonParser::New(); - - Property::Map defaultDirs; - defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ] = DALI_IMAGE_DIR; - defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ] = DALI_SOUND_DIR; - defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR; - defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR; + // Add custom properties + if( OptionalChild customPropertiesChild = IsChild(node, childName) ) + { + const TreeNode& customPropertiesNode = *customPropertiesChild; + const TreeConstIter endIter = customPropertiesNode.CEnd(); + for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter ) + { + const TreeNode::KeyNodePair& keyChild = *iter; + std::string key( keyChild.first ); + Property::Value value; + DeterminePropertyFromNode( keyChild.second, value, constant ); - AddConstants( defaultDirs ); + // Register/Set property. + handle.RegisterProperty( key, value, accessMode ); + } + } } -Builder::~Builder() -{ -} } // namespace Internal diff --git a/dali-toolkit/internal/builder/builder-impl.h b/dali-toolkit/internal/builder/builder-impl.h index 4c018aa..b6db52d 100644 --- a/dali-toolkit/internal/builder/builder-impl.h +++ b/dali-toolkit/internal/builder/builder-impl.h @@ -34,6 +34,7 @@ #include #include #include +#include // Warning messages usually displayed #define DALI_SCRIPT_WARNING(format, args...) \ @@ -149,6 +150,24 @@ public: bool ApplyStyle( const std::string& styleName, Handle& handle ); /** + * Lookup the stylename in builder. If it's found in the parse tree, + * then return true. + * @param[in] styleName The style name to search for + * @return true if the stylename exists + */ + bool LookupStyleName( const std::string& styleName ); + + /** + * Lookup the stylename in the recorded Styles - if it exists, + * performs a shallow copy to the passed in style and returns true. + * Otherwise it returns false. + + * @param[in] styleName The stylename to search for + * @return A const pointer to the style object + */ + const StylePtr GetStyle( const std::string& styleName ); + + /** * @copydoc Toolkit::Builder::AddActors */ void AddActors( Actor toActor ); @@ -214,99 +233,151 @@ public: */ void EmitQuitSignal(); + protected: virtual ~Builder(); private: - // Undefined - Builder(const Builder&); - Builder& operator=(const Builder& rhs); - - void SetupTask( RenderTask& task, const Toolkit::TreeNode& node, const Replacement& replacement ); - - void SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, const std::string& childName, Property::AccessMode accessMode ); - -private: - Toolkit::JsonParser mParser; - - typedef std::map ImageLut; - ImageLut mFrameBufferImageLut; - - typedef std::map PathLut; - PathLut mPathLut; - - typedef struct{ std::string name; Dali::PathConstrainer pathConstrainer; } PathConstrainerEntry; - typedef std::vector PathConstrainerLut; - PathConstrainerLut mPathConstrainerLut; - + typedef std::vector KeyStack; + typedef std::vector< TreeNode::KeyNodePair > MappingsLut; typedef struct{ std::string name; Dali::LinearConstrainer linearConstrainer; } LinearConstrainerEntry; typedef std::vector LinearConstrainerLut; - LinearConstrainerLut mLinearConstrainerLut; - - SlotDelegate mSlotDelegate; - - Property::Map mReplacementMap; - - typedef std::vector< TreeNode::KeyNodePair > MappingsLut; - MappingsLut mCompleteMappings; + typedef struct{ std::string name; Dali::PathConstrainer pathConstrainer; } PathConstrainerEntry; + typedef std::vector PathConstrainerLut; + typedef std::map PathLut; + typedef std::map ImageLut; - BaseHandle Create( const std::string& templateName, const Replacement& constant ); +private: + // Undefined + Builder(const Builder&); - BaseHandle DoCreate( const TreeNode& root, const TreeNode& node, Actor parent, const Replacement& replacements ); + // Undefined + Builder& operator=(const Builder& rhs); void LoadConstants( const TreeNode& root, Property::Map& intoMap ); - void LoadIncludes( const std::string& data ); - - bool ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement); - - Animation CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ); - - typedef std::vector KeyStack; + Animation CreateAnimation( const std::string& animationName, + const Replacement& replacement, + Dali::Actor sourceActor ); + + BaseHandle Create( const std::string& templateName, + const Replacement& constant ); + + BaseHandle DoCreate( const TreeNode& root, + const TreeNode& node, + Actor parent, + const Replacement& replacements ); + + void SetupTask( RenderTask& task, + const Toolkit::TreeNode& node, + const Replacement& replacement ); + + bool ApplyStyle( const std::string& styleName, + Handle& handle, + const Replacement& replacement); + + void ApplyAllStyleProperties( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); + + void RecordStyles( const char* styleName, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& replacements ); + + void RecordStyle( StylePtr style, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& replacements ); + + void ApplyProperties( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); + + void ApplySignals( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle ); + + void ApplyStylesByActor( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); + + void SetProperties( const TreeNode& node, + Handle& handle, + const Replacement& constant ); + + bool MapToTargetProperty( Handle& propertyObject, + const std::string& key, + const TreeNode& node, + const Replacement& constant, + Property::Index& index, + Property::Value& value ); /** - * Tests if the value is a string delimited by <>. If it is, then it attempts to - * change the value to the mapping from a matching key in the mappings table. + * Find the key in the mapping table, if it's present, then generate + * a property value for it (of the given type if available), + * recursing as necessary, and stopping if any cycles are detected. + * * @param[in] mappingRoot The JSON node containing the mappings - * @param[in,out] keyStack the stack of visited keys + * @param[in] theKey The key to search for + * @param[in] propertyType The property type if known, or NONE * @param[in,out] value The string value to test and write back to. - * @return true if the value was converted, false otherwise. */ - bool ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& value ); + bool GetPropertyMap( const TreeNode& mappingRoot, + const char* theKey, + Property::Type propertyType, + Property::Value& value ); + + void SetCustomProperties( const TreeNode& node, + Handle& handle, + const Replacement& constant, + const std::string& childName, + Property::AccessMode accessMode ); /** - * Find the key in the mapping table, if it's present, then generate a property value for it (of the given type if available), recursing as necessary, and stopping if any cycles - * are detected. + * Find the key in the mapping table, if it's present, then generate + * a property value for it (of the given type if available), + * recursing as necessary, and stopping if any cycles are detected. + * * @param[in] mappingRoot The JSON node containing the mappings * @param[in] theKey The key to search for * @param[in,out] keyStack the stack of visited keys * @param[in] propertyType The property type if known, or NONE * @param[in,out] value The string value to test and write back to. */ - bool RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ); + bool RecursePropertyMap( const TreeNode& mappingRoot, + KeyStack& keyStack, + const char* theKey, + Property::Type propertyType, + Property::Value& value ); + /** - * Find the key in the mapping table, if it's present, then generate a property value for it (of the given type if available), recursing as necessary, and stopping if any cycles - * are detected. + * Tests if the value is a string delimited by <>. If it is, then it attempts to + * change the value to the mapping from a matching key in the mappings table. * @param[in] mappingRoot The JSON node containing the mappings - * @param[in] theKey The key to search for - * @param[in] propertyType The property type if known, or NONE + * @param[in,out] keyStack the stack of visited keys * @param[in,out] value The string value to test and write back to. + * @return true if the value was converted, false otherwise. */ - bool GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ); - - void ApplyProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void ApplyStylesByActor( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ); + bool ConvertChildValue( const TreeNode& mappingRoot, + KeyStack& keyStack, + Property::Value& value ); +private: + Toolkit::JsonParser mParser; + ImageLut mFrameBufferImageLut; + PathLut mPathLut; + PathConstrainerLut mPathConstrainerLut; + LinearConstrainerLut mLinearConstrainerLut; + SlotDelegate mSlotDelegate; + Property::Map mReplacementMap; + MappingsLut mCompleteMappings; + Dictionary mStyles; // State based styles Toolkit::Builder::BuilderSignalType mQuitSignal; }; diff --git a/dali-toolkit/internal/builder/builder-set-property.cpp b/dali-toolkit/internal/builder/builder-set-property.cpp index d64a04c..93a1fbe 100644 --- a/dali-toolkit/internal/builder/builder-set-property.cpp +++ b/dali-toolkit/internal/builder/builder-set-property.cpp @@ -19,13 +19,13 @@ #include #include #include -#include // INTERNAL INCLUDES #include #include #include #include +#include namespace Dali { @@ -36,29 +36,6 @@ namespace Toolkit namespace Internal { - -namespace -{ - -/** - * Converts a HTML style 'color' hex string ("#FF0000" for bright red) to a Vector4. - * The Vector4 alpha component will be set to 1.0f - * @param hexString The HTML style hex string - * @return a Vector4 containing the new color value - */ -Vector4 HexStringToVector4( const char* s ) -{ - unsigned int value(0u); - std::istringstream( s ) >> std::hex >> value; - return Vector4( ((value >> 16 ) & 0xff ) / 255.0f, - ((value >> 8 ) & 0xff ) / 255.0f, - (value & 0xff ) / 255.0f, - 1.0f ); -} - -} // anon namespace - - /** * A property value type can be forced when its unknown by a disambiguation convention in the json * ie "myarray": [1,2,3,4] ; would be a vector but @@ -194,17 +171,9 @@ bool DeterminePropertyFromNode( const TreeNode& node, Property::Type type, Prope } else if( OptionalString s = replacer.IsString(node) ) { - if( (*s)[0] == '#' && 7 == (*s).size() ) - { - value = HexStringToVector4( &(*s)[1] ); - done = true; - } - else if( Dali::ColorController::Get() ) - { - Vector4 color; - done = Dali::ColorController::Get().RetrieveColor( *s, color ); - value = color; - } + Vector4 color; + done = ConvertStringToColor( *s, color ); + value = color; } else if( TreeNode::OBJECT == node.GetType() ) { diff --git a/dali-toolkit/internal/builder/dictionary.h b/dali-toolkit/internal/builder/dictionary.h new file mode 100644 index 0000000..22d2afe --- /dev/null +++ b/dali-toolkit/internal/builder/dictionary.h @@ -0,0 +1,235 @@ +#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H +#define DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H + +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace Dali +{ +extern bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b ); + +namespace Toolkit +{ +namespace Internal +{ + +/** + * The Dictionary template class enables a means of storing key-value + * pairs where the keys are strings and the value can be a complex + * type. + * + * It enables lookup of keys via case-insensitive match. + */ +template +class Dictionary +{ +private: + /** + * Element is a key-value pair + */ + struct Element + { + std::string key; + EntryType entry; + Element( const std::string&name, EntryType entry ) + : key( name ), + entry( entry ) + { + } + }; + typedef std::vector Elements; + Elements container; + +public: + /** + * Only allow const iteration over the dictionary + */ + typedef typename Elements::const_iterator iterator; + + + /** + * Constructor + */ + Dictionary() + { + } + + /** + * Add a key value pair to the dictionary. + * If the entry does not already exist, add it to the dictionary + * using a shallow copy + */ + bool Add( const std::string& name, const EntryType& entry ) + { + for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter ) + { + if( iter->key == name ) + { + return false; + } + } + container.push_back( Element(name, entry) ); + return true; + } + + /** + * Add a key-value pair to the dictionary + * If the entry does not already exist, add it to the dictionary + * (shallow copy) + */ + bool Add( const char* name, const EntryType& entry ) + { + bool result=false; + if( name != NULL ) + { + std::string theName(name); + result=Add(theName, entry); + } + return result; + } + + /** + * Find the element in the dictionary pointed at by key, and + * return a pointer to it, or NULL. + */ + EntryType* Find( const std::string& key ) const + { + EntryType* result=NULL; + + if( ! key.empty() ) + { + for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter ) + { + if( iter->key == key ) + { + result = &(iter->entry); + break; + } + } + } + return result; + } + + /** + * Find the element in the dictionary pointed at by key, and + * return a pointer to it, or NULL + */ + EntryType* Find( const char* key ) const + { + if( key != NULL ) + { + std::string theKey(key); + return Find(theKey); + } + return NULL; + } + + /** + * Find the element in the dictionary pointed at by key using a case + * insensitive search, and return a const pointer to it, or NULL + */ + const EntryType* FindCaseInsensitiveC( const std::string& key ) const + { + if( ! key.empty() ) + { + for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter ) + { + if( Dali::CaseInsensitiveStringCompare(iter->key, key )) + { + const EntryType* result = &(iter->entry); + return result; + } + } + } + return NULL; + } + + /** + * Find the element in the dictionary pointed at by key using a case + * insensitive search, and return a non-const pointer to it, or NULL + */ + EntryType* FindCaseInsensitive( const std::string& key ) const + { + EntryType* result = NULL; + if( ! key.empty() ) + { + for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter ) + { + if( Dali::CaseInsensitiveStringCompare(iter->key, key )) + { + // Const cast because of const_iterator. const_iterator because, STL. + result = const_cast(&(iter->entry)); + } + } + } + return result; + } + + /** + * Find the element in the dictionary pointed at by key using a case + * insensitive search, and return a const pointer to it, or NULL + */ + const EntryType* FindCaseInsensitiveC( const char* key ) const + { + if( key != NULL ) + { + std::string theKey(key); + return FindCaseInsensitiveC( theKey ); + } + return NULL; + } + + /** + * Find the element in the dictionary pointed at by key using a case + * insensitive search, and return a non-const pointer to it, or NULL + */ + EntryType* FindCaseInsensitive( const char* key ) const + { + if( key != NULL ) + { + std::string theKey(key); + return FindCaseInsensitive( theKey ); + } + return NULL; + } + + /** + * Return an iterator pointing at the first entry in the dictionary + */ + typename Elements::const_iterator Begin() const + { + return container.begin(); + } + + /** + * Return an iterator pointing past the last entry in the dictionary + */ + typename Elements::const_iterator End() const + { + return container.end(); + } +}; + + + +}//Internal +}//Toolkit +}//Dali + +#endif // DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H diff --git a/dali-toolkit/internal/builder/style.cpp b/dali-toolkit/internal/builder/style.cpp new file mode 100644 index 0000000..eaf59dc --- /dev/null +++ b/dali-toolkit/internal/builder/style.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ + +StylePtr Style::New() +{ + StylePtr stylePtr( new Style() ); + return stylePtr; +} + +void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const +{ + ApplyVisuals( handle ); + ApplyProperties( handle ); + + Toolkit::Control control = Toolkit::Control::DownCast(handle); + if( control ) + { + Property::Value value = control.GetProperty(DevelControl::Property::STATE); + std::string stateName; + if( value.Get( stateName ) ) + { + // Look up state in states table: + const StylePtr* stylePtr = subStates.FindCaseInsensitiveC( stateName ); + if( stylePtr ) + { + const StylePtr statePtr(*stylePtr); + + // We have a state match. + statePtr->ApplyVisuals( handle ); + statePtr->ApplyProperties( handle ); + + // Apply substate visuals + Property::Value value = control.GetProperty(DevelControl::Property::SUB_STATE); + std::string subStateName; + if( value.Get( subStateName ) && ! subStateName.empty() ) + { + const StylePtr* stylePtr = statePtr->subStates.FindCaseInsensitiveC( subStateName ); + if( stylePtr ) + { + const StylePtr subStatePtr(*stylePtr); + // We have a sub-state match. + subStatePtr->ApplyVisuals( handle ); + subStatePtr->ApplyProperties( handle ); + } + } + } + } + } +} + +void Style::ApplyVisuals( Handle handle ) const +{ + for( Dictionary::iterator iter = visuals.Begin(); iter != visuals.End() ; ++iter ) + { + const std::string& visualName = (*iter).key; + const Property::Map& map = (*iter).entry; + Dali::Property::Index index = handle.GetPropertyIndex( visualName ); + if( index != Property::INVALID_INDEX ) + { + const Property::Value value(const_cast(map)); + handle.SetProperty( index, value ); + } + } +} + +void Style::ApplyProperties( Handle handle ) const +{ + for( Property::Map::SizeType i=0; i +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ + +class Style; +typedef IntrusivePtr