On state change, visuals now keep instance data 36/116336/7
authorDavid Steele <david.steele@samsung.com>
Thu, 23 Feb 2017 21:31:41 +0000 (21:31 +0000)
committerDavid Steele <david.steele@samsung.com>
Fri, 3 Mar 2017 13:32:30 +0000 (13:32 +0000)
If a visual such as a text visual has instance data (i.e. the text string)
ensure that this is applied following a state change where the visual
is removed and re-added.

Added new method CreateInstancePropertyMap to Visual::Base::Impl,
and methods DoCreateInstancePropertyMap to derived visuals for writing instance data
into. So far, this is for text visual's text property and image visual's desired image
size properties.

TODO: Prevent the visual being re-added if no properties change
(or only animatable properties change) (Whilst taking into account string vs index keys; Property Array vs Vector...

[ Note: this is problematic for gradient visual, which generates a bunch of property arrays whilst Builder has generated Vectors from the equivalent JSON ]

Change-Id: I742c47067fc19fbaeee2f01195f6f00501b16c85
Signed-off-by: David Steele <david.steele@samsung.com>
33 files changed:
automated-tests/src/dali-toolkit-styling/default-theme.json
automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h
dali-toolkit/internal/builder/builder-impl.cpp
dali-toolkit/internal/builder/dictionary.h
dali-toolkit/internal/builder/style.cpp
dali-toolkit/internal/builder/style.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/border/border-visual.cpp
dali-toolkit/internal/visuals/border/border-visual.h
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.h
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/gradient/gradient-visual.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/mesh/mesh-visual.cpp
dali-toolkit/internal/visuals/mesh/mesh-visual.h
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.h
dali-toolkit/internal/visuals/primitive/primitive-visual.cpp
dali-toolkit/internal/visuals/primitive/primitive-visual.h
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.h
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h
dali-toolkit/internal/visuals/wireframe/wireframe-visual.cpp
dali-toolkit/internal/visuals/wireframe/wireframe-visual.h
dali-toolkit/public-api/controls/control-impl.cpp

index aea0422..4f9fb77 100644 (file)
             {
               "visuals":
               {
-                "foregroundVisual":
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0001.png"
+                },
+                "testVisual2":
                 {
                   "visualType":"GRADIENT",
                   "startPosition": [-1, -1],
                   "spreadMethod": "REPEAT",
                   "stopOffset": [0.2, 0.8],
                   "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+                },
+                "foregroundVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"theSameImage.png"
+                },
+                "labelVisual":
+                {
+                  "visualType":"TEXT",
+                  "pointSize":8,
+                  "text":"Some text"
                 }
               }
             },
             {
               "visuals":
               {
-                "foregroundVisual":
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0002.png"
+                },
+                "testVisual2":
                 {
                   "visualType":"COLOR",
                   "mixColor": [ 1,0,0,1]
+                },
+                "foregroundVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"theSameImage.png"
+                },
+                "labelVisual":
+                {
+                  "visualType":"TEXT",
+                  "pointSize":8,
+                  "text":"Some different text"
                 }
               }
             }
             },
             "focusVisual":
             {
-              "visualType":"IMAGE",
-              "url": "focus.png"
+              "visualType":"NPATCH",
+              "url": "focus.9.png"
             }
           },
           "entryTransition":
         },
         "DISABLED":
         {
+          "states":
+          {
+            "SELECTED":
+            {
+              "visuals":
+              {
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0001.png"
+                },
+                "testVisual2":
+                {
+                  "visualType":"GRADIENT",
+                  "startPosition": [-1, -1],
+                  "endPosition": [1, 1],
+                  "spreadMethod": "REPEAT",
+                  "stopOffset": [0.2, 0.8],
+                  "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+                }
+              }
+            }
+          },
           "visuals":
           {
             "foregroundVisual":
               "spreadMethod": "REPEAT",
               "stopOffset": [0.2, 0.8],
               "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+            },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":8,
+              "textColor":[1,0,1,1]
             }
           }
         },
               "stopOffset": [0.3, 0.9],
               "stopColor": [ [ 0,0,1,1], [0,1,1,1] ]
             },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":10
+            },
             "focusVisual":
             {
               "visualType":"IMAGE",
             {
               "visualType":"COLOR",
               "mixColor": [1,0,0,1]
+            },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":9,
+              "textColor":[1,1,1,1]
             }
           }
         }
           }
         }
       ]
+    },
+    "NoStateStyle":
+    {
+      "testVisual2":
+      {
+        "visualType":"COLOR",
+        "mixColor":[1,1,1,1]
+      }
     }
   }
 }
index 34f604a..6a81e06 100644 (file)
@@ -29,6 +29,8 @@
 #include <toolkit-style-monitor.h>
 #include <dummy-control.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
 
 using namespace Dali;
@@ -56,6 +58,54 @@ void dali_style_manager_cleanup(void)
   test_return_value = TET_PASS;
 }
 
+
+Visual::Base CheckVisual( Impl::DummyControl& dummyImpl, Property::Index visualId, int type, const char* location )
+{
+    DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(visualId), true, location);
+    Visual::Base visual = dummyImpl.GetVisual(visualId);
+    DALI_TEST_EQUALS( (bool)visual, true, location );
+    Property::Map map;
+    visual.CreatePropertyMap( map );
+    Property::Value* value = map.Find( Visual::Property::TYPE );
+    DALI_TEST_EQUALS( value != NULL, true, location );
+
+    int visualType;
+    value->Get( visualType );
+    DALI_TEST_EQUALS( visualType, type, location );
+    return visual;
+}
+
+
+Integration::Bitmap* CreateBitmap( unsigned int imageWidth, unsigned int imageHeight, unsigned int initialColor, Pixel::Format pixelFormat )
+{
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
+  Integration::PixelBuffer* pixbuffer = bitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, imageWidth, imageHeight, imageWidth, imageHeight );
+  unsigned int bytesPerPixel = GetBytesPerPixel( pixelFormat );
+
+  memset( pixbuffer, initialColor, imageHeight * imageWidth * bytesPerPixel );
+
+  return bitmap;
+}
+
+Integration::ResourcePointer CustomizeNinePatch( TestApplication& application,
+                                                 unsigned int ninePatchImageWidth,
+                                                 unsigned int ninePatchImageHeight)
+{
+  TestPlatformAbstraction& platform = application.GetPlatform();
+
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+
+  tet_infoline("Create Bitmap");
+  platform.SetClosestImageSize(Vector2( ninePatchImageWidth, ninePatchImageHeight));
+  Integration::Bitmap* bitmap = CreateBitmap( ninePatchImageWidth, ninePatchImageHeight, 0xFF, pixelFormat );
+
+  tet_infoline("Getting resource");
+  Integration::ResourcePointer resourcePtr(bitmap);
+  platform.SetSynchronouslyLoadedResource( resourcePtr);
+
+  return resourcePtr;
+}
+
 int UtcDaliStyleManagerConstructorP(void)
 {
   ToolkitTestApplication application;
@@ -884,17 +934,38 @@ int UtcDaliStyleManagerSetState01(void)
   Stage::GetCurrent().Add(actor);
 
   Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
 
   DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
   Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  Visual::Base labelVisual1 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  Property::Map labelMap;
+  labelVisual1.CreatePropertyMap( labelMap );
+  labelMap[TextVisual::Property::TEXT] = "New text";
+  VisualFactory factory = VisualFactory::Get();
+  labelVisual1 = factory.CreateVisual(labelMap);
+  dummyImpl.UnregisterVisual(DummyControl::Property::LABEL_VISUAL );
+  dummyImpl.RegisterVisual(DummyControl::Property::LABEL_VISUAL, labelVisual1 );
 
   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);
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::LABEL_VISUAL), true, TEST_LOCATION);
 
   Visual::Base visual2 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  Visual::Base labelVisual2 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
   DALI_TEST_CHECK( visual1 != visual2 );
+  DALI_TEST_CHECK( labelVisual1 != labelVisual2 );
+  labelMap.Clear();
+  labelVisual2.CreatePropertyMap( labelMap );
+  Property::Value* textValue = labelMap.Find( Toolkit::TextVisual::Property::TEXT, "text");
+  DALI_TEST_CHECK( textValue );
+  Property::Value* pointSizeValue = labelMap.Find( Toolkit::TextVisual::Property::POINT_SIZE, "pointSize");
+  tet_infoline( "Check that the instance data has been copied to the new text visual\n");
+  DALI_TEST_EQUALS( textValue->Get<std::string>(), "New text", TEST_LOCATION );
+  DALI_TEST_EQUALS( pointSizeValue->Get<int>(), 10, TEST_LOCATION );
+
 
   actor.SetProperty( DevelControl::Property::STATE, DevelControl::DISABLED );
 
@@ -908,6 +979,17 @@ int UtcDaliStyleManagerSetState01(void)
   DALI_TEST_CHECK( visual1 != visual3 );
   DALI_TEST_CHECK( visual2 != visual3 );
 
+  Visual::Base labelVisual3 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( labelVisual2 != labelVisual3 );
+
+  labelVisual2.CreatePropertyMap( labelMap );
+  textValue = labelMap.Find(Toolkit::TextVisual::Property::TEXT, "text");
+  DALI_TEST_CHECK( textValue );
+  pointSizeValue = labelMap.Find(Toolkit::TextVisual::Property::POINT_SIZE, "pointSize");
+  tet_infoline( "Check that the instance data has been copied to the new text visual\n");
+  DALI_TEST_EQUALS( textValue->Get<std::string>(), "New text", TEST_LOCATION );
+  DALI_TEST_EQUALS( pointSizeValue->Get<int>(), 10, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -928,6 +1010,7 @@ int UtcDaliStyleManagerSetState02(void)
   Stage::GetCurrent().Add(actor);
 
   Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
 
   int state = actor.GetProperty<int>( DevelControl::Property::STATE );
   DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
@@ -956,9 +1039,16 @@ int UtcDaliStyleManagerSetState02(void)
   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);
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL2);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( testVisual );
+
 
   DALI_TEST_CHECK( visual1 != visual3 );
   DALI_TEST_CHECK( visual2 != visual3 );
@@ -974,7 +1064,7 @@ int UtcDaliStyleManagerSetState02(void)
   visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
   DALI_TEST_CHECK( visual1 );
 
-  focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_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);
 
@@ -983,7 +1073,104 @@ int UtcDaliStyleManagerSetState02(void)
 }
 
 
-int UtcDaliStyleManagerSetSubState(void)
+int UtcDaliStyleManagerSetState03N(void)
+{
+  tet_infoline("Instantiate dummy control and test state transition without state style" );
+  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("NoStyles");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  int state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "FOCUSED" ).Add("withTransitions", false));
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::FOCUSED, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "DISABLED" ).Add("withTransitions", false));
+
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::DISABLED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetState04N(void)
+{
+  tet_infoline("Instantiate dummy control and test state transition with style without state" );
+  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("NoStateStyle");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  int state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "FOCUSED" ).Add("withTransitions", false));
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::FOCUSED, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "DISABLED" ).Add("withTransitions", false));
+
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::DISABLED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerSetSubState01(void)
 {
   tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
   Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
@@ -1001,53 +1188,97 @@ int UtcDaliStyleManagerSetSubState(void)
   actor.SetStyleName("ComplexControl");
   Stage::GetCurrent().Add(actor);
 
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
   Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
 
-  {
-    DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
-    Visual::Base visual = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
-    DALI_TEST_CHECK( visual );
-    Property::Map map;
-    visual.CreatePropertyMap( map );
-    Property::Value* value = map.Find( Visual::Property::TYPE );
-    DALI_TEST_CHECK( value );
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
 
-    int visualType;
-    value->Get( visualType );
-    DALI_TEST_EQUALS( visualType, (int)Toolkit::Visual::GRADIENT, TEST_LOCATION );
-  }
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "UNSELECTED");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::COLOR, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetSubState02(void)
+{
+  tet_infoline("Instantiate complex control and test state/substate change" );
+  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, "NORMAL");
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+  tet_infoline( "Setting state to NORMAL/SELECTED before re-styling\n");
+
+  actor.SetStyleName("ComplexControl");
+  Stage::GetCurrent().Add(actor);
+
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
 
   actor.SetProperty(DevelControl::Property::SUB_STATE, "UNSELECTED");
+  tet_infoline( "Changing substate to UNSELECTED - check visual changes\n");
 
-  {
-    DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
-    Visual::Base visual = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
-    DALI_TEST_CHECK( visual );
-    Property::Map map;
-    visual.CreatePropertyMap( map );
-    Property::Value* value = map.Find( Visual::Property::TYPE );
-    DALI_TEST_CHECK( value );
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::COLOR, TEST_LOCATION);
 
-    int visualType;
-    value->Get( visualType );
-    DALI_TEST_EQUALS( visualType, (int)Toolkit::Visual::COLOR, TEST_LOCATION );
-  }
+  actor.SetProperty(DevelControl::Property::STATE, "FOCUSED");
+  tet_infoline( "Changing state to FOCUSED - check visual changes\n");
+
+  Visual::Base fgVisual1 = CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+  Visual::Base focusVisual1 = CheckVisual( dummyImpl, DummyControl::Property::FOCUS_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
 
   actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+  tet_infoline( "Changing  substate to SELECTED - Expect no change\n");
 
-  {
-    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
-    DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
-    Visual::Base visual = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
-    DALI_TEST_CHECK( visual );
-    Property::Map map;
-    visual.CreatePropertyMap( map );
-    Property::Value* value = map.Find( Visual::Property::TYPE );
-    DALI_TEST_CHECK( value );
+  Visual::Base fgVisual2 = CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+  Visual::Base focusVisual2 = CheckVisual( dummyImpl, DummyControl::Property::FOCUS_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+
+  DALI_TEST_CHECK( fgVisual1 == fgVisual2 );
+  DALI_TEST_CHECK( focusVisual1 == focusVisual2 );
+
+  actor.SetProperty(DevelControl::Property::STATE, "NORMAL");
+  tet_infoline( "Changing state to NORMAL - Expect to change to NORMAL/SELECTED \n");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( ! focusVisual );
+
+  actor.SetProperty(DevelControl::Property::STATE, "DISABLED");
+  tet_infoline( "Changing state to DISABLED - Expect to change to DISABLED/SELECTED \n");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::COLOR, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( ! testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( ! testVisual );
 
-    int visualType;
-    value->Get( visualType );
-    DALI_TEST_EQUALS( visualType, (int)Toolkit::Visual::GRADIENT, TEST_LOCATION );
-  }
   END_TEST;
 }
index 979e56a..8f70228 100644 (file)
@@ -72,7 +72,7 @@ Dali::PropertyRegistration dummyControlVisualProperty01(
   typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
 
 Dali::PropertyRegistration dummyControlVisualProperty02(
-  typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "testVisual2", 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 );
@@ -80,6 +80,9 @@ Dali::PropertyRegistration dummyControlVisualProperty03(
 Dali::PropertyRegistration dummyControlVisualProperty04(
   typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
 
+Dali::PropertyRegistration dummyControlVisualProperty05(
+  typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
 }
 
 DummyControl DummyControlImpl::New()
@@ -125,6 +128,12 @@ void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::B
 void DummyControlImpl::UnregisterVisual( Property::Index index )
 {
   Control::UnregisterVisual( index );
+
+  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+  if( iter != mRegisteredVisualIndices.end() )
+  {
+    mRegisteredVisualIndices.erase(iter);
+  }
 }
 
 Toolkit::Visual::Base DummyControlImpl::GetVisual( Property::Index index )
@@ -142,7 +151,6 @@ bool DummyControlImpl::IsVisualEnabled( Property::Index index )
   return Control::IsVisualEnabled( index );
 }
 
-
 Animation DummyControlImpl::CreateTransition( const Toolkit::TransitionData& transition )
 {
   return Control::CreateTransition( transition );
@@ -159,6 +167,7 @@ void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index in
     case Toolkit::DummyControl::Property::TEST_VISUAL2:
     case Toolkit::DummyControl::Property::FOREGROUND_VISUAL:
     case Toolkit::DummyControl::Property::FOCUS_VISUAL:
+    case Toolkit::DummyControl::Property::LABEL_VISUAL:
     {
       Property::Map* map = value.GetMap();
       if( map != NULL )
index 75d3efe..d4b8b18 100644 (file)
@@ -48,7 +48,8 @@ public:
       TEST_VISUAL = PROPERTY_START_INDEX,
       TEST_VISUAL2,
       FOREGROUND_VISUAL,
-      FOCUS_VISUAL
+      FOCUS_VISUAL,
+      LABEL_VISUAL
     };
   };
 
@@ -92,7 +93,7 @@ public:
   void UnregisterVisual( Property::Index index );
   void EnableVisual( Property::Index index, bool enabled );
   bool IsVisualEnabled( Property::Index index );
-
+  int GetVisualCount();
   Toolkit::Visual::Base GetVisual( Property::Index index );
   Animation CreateTransition( const Toolkit::TransitionData& transition );
 
index 48d2e2b..e4ef639 100644 (file)
@@ -1139,7 +1139,8 @@ void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& nod
   if( matchedStyle )
   {
     StylePtr style( *matchedStyle );
-    style->ApplyVisualsAndPropertiesRecursively( handle ); // (recurses through states)
+    Dictionary<Property::Map> instancedProperties;
+    style->ApplyVisualsAndPropertiesRecursively( handle, instancedProperties );
   }
   else // If there were no styles, instead set properties
   {
index ccccf2c..88095eb 100644 (file)
@@ -36,6 +36,23 @@ namespace Internal
  *
  * It enables lookup of keys via case-insensitive match.
  */
+
+
+typedef std::vector<std::string> DictionaryKeys;
+inline void Merge( DictionaryKeys& toDict, const DictionaryKeys& fromDict )
+{
+  for( DictionaryKeys::const_iterator fromIter = fromDict.begin(); fromIter != fromDict.end(); ++fromIter )
+  {
+    const std::string& fromKey = (*fromIter);
+    DictionaryKeys::iterator toIter = std::find( toDict.begin(), toDict.end(), fromKey );
+    if( toIter == toDict.end() )
+    {
+      toDict.push_back( fromKey );
+    }
+  }
+}
+
+
 template<typename EntryType>
 class Dictionary
 {
@@ -62,7 +79,6 @@ public:
    */
   typedef typename Elements::const_iterator iterator;
 
-
   /**
    * Constructor
    */
@@ -105,6 +121,53 @@ public:
   }
 
   /**
+   * Remove a key value pair from the dictionary.
+   */
+  void Remove( const std::string& name )
+  {
+    for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter )
+    {
+      if( iter->key == name )
+      {
+        container.erase( iter );
+        break;
+      }
+    }
+  }
+
+  /**
+   * Remove a key value pair from the dictionary.
+   */
+  void Remove( const char* name )
+  {
+    if( name != NULL )
+    {
+      std::string theName(name);
+      Remove(theName);
+    }
+  }
+
+  void Merge( const Dictionary<EntryType>& dictionary )
+  {
+    for( typename Elements::const_iterator fromIter = dictionary.container.begin(); fromIter != dictionary.container.end(); ++fromIter )
+    {
+      bool found=false;
+      for( typename Elements::iterator toIter = container.begin(); toIter != container.end(); ++toIter )
+      {
+        if( fromIter->key == toIter->key )
+        {
+          found=true;
+          toIter->entry = fromIter->entry;
+        }
+      }
+      if( !found )
+      {
+        container.push_back( Element(fromIter->key, fromIter->entry) );
+      }
+    }
+  }
+
+  /**
    * Find the element in the dictionary pointed at by key, and
    * insensitive search, and return a const pointer to it, or NULL
    */
@@ -187,6 +250,20 @@ public:
   {
     return container.end();
   }
+
+  void GetKeys( DictionaryKeys& keys ) const
+  {
+    keys.clear();
+    for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+    {
+      keys.push_back( (*iter).key );
+    }
+  }
+
+  void Clear()
+  {
+    container.clear();
+  }
 };
 
 
index 515ddd9..988bd61 100644 (file)
@@ -18,7 +18,9 @@
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/internal/builder/style.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
 
 namespace Dali
 {
@@ -37,9 +39,11 @@ StylePtr Style::New()
   return stylePtr;
 }
 
-void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const
+void Style::ApplyVisualsAndPropertiesRecursively(
+  Handle handle,
+  const Dictionary<Property::Map>& instancedProperties ) const
 {
-  ApplyVisuals( handle );
+  ApplyVisuals( handle, instancedProperties );
   ApplyProperties( handle );
 
   Toolkit::Control control = Toolkit::Control::DownCast(handle);
@@ -59,7 +63,7 @@ void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const
         const StylePtr statePtr(*stylePtr);
 
         // We have a state match.
-        statePtr->ApplyVisuals( handle );
+        statePtr->ApplyVisuals( handle, instancedProperties );
         statePtr->ApplyProperties( handle );
 
         // Apply substate visuals
@@ -72,7 +76,7 @@ void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const
           {
             const StylePtr subStatePtr(*stylePtr);
             // We have a sub-state match.
-            subStatePtr->ApplyVisuals( handle );
+            subStatePtr->ApplyVisuals( handle, instancedProperties );
             subStatePtr->ApplyProperties( handle );
           }
         }
@@ -81,18 +85,66 @@ void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const
   }
 }
 
-void Style::ApplyVisuals( Handle handle ) const
+void Style::ApplyVisuals(
+  Handle handle,
+  const Dictionary<Property::Map>& instancedProperties ) const
 {
-  for( Dictionary<Property::Map>::iterator iter = visuals.Begin(); iter != visuals.End() ; ++iter )
+  ApplyVisuals( handle, visuals, instancedProperties );
+}
+
+void Style::ApplyVisuals(
+  Handle handle,
+  const Dictionary<Property::Map>& visualMaps,
+  const Dictionary<Property::Map>& instancedProperties )
+{
+  for( Dictionary<Property::Map>::iterator iter = visualMaps.Begin(); iter != visualMaps.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 )
+    Property::Map map = (*iter).entry;
+    Property::Map* instancedMap = instancedProperties.Find( visualName );
+    ApplyVisual( handle, visualName, map, instancedMap );
+  }
+}
+
+void Style::ApplyVisual(
+  Handle handle,
+  const std::string& visualName,
+  const Property::Map& visualMap,
+  const Property::Map* instancedProperties )
+{
+  // Check if this visual name is a valid property of handle
+  Dali::Property::Index index = handle.GetPropertyIndex( visualName );
+  if( index != Property::INVALID_INDEX )
+  {
+    const Property::Map* applyMap = &visualMap;
+    Property::Map mergedMap;
+
+    // If there are instanced properties, and the visual types match,
+    // merge them into the visual map
+    if( instancedProperties )
     {
-      const Property::Value value(const_cast<Property::Map&>(map));
-      handle.SetProperty( index, value );
+      Property::Value* instanceTypeValue = instancedProperties->Find( Toolkit::DevelVisual::Property::TYPE);
+      Property::Value* newTypeValue = visualMap.Find( Toolkit::DevelVisual::Property::TYPE, VISUAL_TYPE );
+      if( instanceTypeValue && newTypeValue )
+      {
+        int instanceVisualType=-1;
+        int newVisualType=-1;
+        Scripting::GetEnumerationProperty( *instanceTypeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, instanceVisualType );
+        Scripting::GetEnumerationProperty( *newTypeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, newVisualType );
+
+        if( instanceVisualType == newVisualType )
+        {
+          // Same type - merge remaining instance data
+          mergedMap.Merge( visualMap );
+          mergedMap.Merge( *instancedProperties );
+          applyMap = &mergedMap;
+        }
+      }
     }
+
+    // Apply the visual property map to the handle
+    const Property::Value value(const_cast<Property::Map&>(*applyMap));
+    handle.SetProperty( index, value );
   }
 }
 
index bd26a6d..441f568 100644 (file)
@@ -55,16 +55,41 @@ public:
    * through sub-states.
    *
    * @param[in] handle The handle to apply the visuals to
+   * @param[in] instancedProperties The maps from which to get instanced properties
    */
-  void ApplyVisualsAndPropertiesRecursively( Handle handle ) const;
+  void ApplyVisualsAndPropertiesRecursively( Handle handle,
+                                             const Dictionary<Property::Map>& instancedProperties ) const;
 
   /**
    * Apply the visuals of the style to the control pointed at by
    * handle.
    *
    * @param[in] handle The handle to apply the visuals to
+   * @param[in] instancedProperties The maps from which to get instanced properties
    */
-  void ApplyVisuals( Handle handle ) const;
+  void ApplyVisuals( Handle handle,
+                     const Dictionary<Property::Map>& instancedProperties ) const;
+
+  /**
+   * Apply the properties from the visualMaps and the instancedProperties
+   * to the control pointed at by handle.
+   *
+   * @param[in] handle The handle to apply the properties to
+   * @param[in] visualMaps The visual maps from which to get the styled properties
+   * @param[in] instancedProperties The maps from which to get instanced properties
+   */
+  static void ApplyVisuals( Handle handle,
+                            const Dictionary<Property::Map>& visualMaps,
+                            const Dictionary<Property::Map>& instancedProperties );
+
+  /**
+   * Apply the properties from the visualMap and optional instancedProperties
+   * to the control pointed at by handle.
+   */
+  static void ApplyVisual( Handle handle,
+                           const std::string& visualName,
+                           const Property::Map& visualMap,
+                           const Property::Map* instancedProperties );
 
   /**
    * Apply the properties of the style to the control pointed at by
index 2b58ce9..0031bc3 100644 (file)
@@ -113,6 +113,11 @@ void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
 }
 
+void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
 {
   // url already passed in from constructor
index d19fd09..e89fec6 100644 (file)
@@ -99,6 +99,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 13b8633..2329167 100644 (file)
@@ -226,6 +226,11 @@ void BorderVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::BorderVisual::Property::ANTI_ALIASING, mAntiAliasing );
 }
 
+void BorderVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void BorderVisual::OnSetTransform()
 {
   if( mImpl->mRenderer )
index 7efb142..473080b 100644 (file)
@@ -91,6 +91,11 @@ protected:
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
   /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
+  /**
    * @copydoc Visual::Base::OnSetTransform
    */
   virtual void OnSetTransform();
index 0ac80d6..1691888 100644 (file)
@@ -138,6 +138,12 @@ void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor );
 }
 
+void ColorVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+
 void ColorVisual::OnSetTransform()
 {
   if( mImpl->mRenderer )
index e5f6df1..939d40e 100644 (file)
@@ -65,6 +65,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 4ea6a28..fbce369 100644 (file)
@@ -323,6 +323,11 @@ void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
   }
 }
 
+void GradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void GradientVisual::InitializeRenderer()
 {
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
index c64b588..9c84cf2 100644 (file)
@@ -100,6 +100,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index f6e2a9f..aa3c118 100644 (file)
@@ -789,6 +789,22 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
 }
 
+void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::Visual::IMAGE );
+  if( !mImageUrl.empty() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
+  }
+  else if( mImage )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
+  }
+}
+
 void ImageVisual::OnSetTransform()
 {
   if( mImpl->mRenderer )
index 52312ea..b0cc262 100644 (file)
@@ -152,6 +152,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 051dfa3..190c457 100644 (file)
@@ -533,6 +533,11 @@ void MeshVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::MeshVisual::Property::LIGHT_POSITION, mLightPosition );
 }
 
+void MeshVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void MeshVisual::InitializeRenderer()
 {
   //Try to load the geometry from the file.
index 2c227a3..511ce49 100644 (file)
@@ -75,6 +75,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 6ecb818..31e6344 100644 (file)
@@ -324,6 +324,11 @@ void NPatchVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly );
 }
 
+void NPatchVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mLoader( factoryCache.GetNPatchLoader() ),
index 0a0465f..22b60d5 100644 (file)
@@ -100,6 +100,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 748564e..9d306be 100644 (file)
@@ -438,6 +438,11 @@ void PrimitiveVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, mLightPosition );
 }
 
+void PrimitiveVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void PrimitiveVisual::OnSetTransform()
 {
   if( mImpl->mRenderer )
index 6b210bd..677df9d 100644 (file)
@@ -122,6 +122,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index ad352af..73d29e0 100644 (file)
@@ -144,6 +144,11 @@ void SvgVisual::DoCreatePropertyMap( Property::Map& map ) const
   }
 }
 
+void SvgVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void SvgVisual::ParseFromUrl( const std::string& imageUrl )
 {
   mImageUrl = imageUrl;
index 26e7208..3369901 100644 (file)
@@ -90,6 +90,11 @@ public:  // from Visual
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 55b1478..77a680f 100644 (file)
@@ -261,6 +261,16 @@ void TextVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::TextVisual::Property::ENABLE_MARKUP, mController->IsMarkupProcessorEnabled() );
 }
 
+void TextVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::DevelVisual::TEXT );
+  std::string text;
+  mController->GetText( text );
+  map.Insert( Toolkit::TextVisual::Property::TEXT, text );
+}
+
+
 TextVisual::TextVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mController( Text::Controller::New() ),
index b0bf8c3..b11f548 100644 (file)
@@ -98,6 +98,11 @@ public: // from Visual::Base
    */
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
 protected:
 
   /**
index 0d2b050..bfd5293 100644 (file)
@@ -287,6 +287,20 @@ void Visual::Base::CreatePropertyMap( Property::Map& map ) const
   map.Insert( DevelVisual::Property::OPACITY, mImpl->mMixColor.a );
 }
 
+void Visual::Base::CreateInstancePropertyMap( Property::Map& map ) const
+{
+  DoCreateInstancePropertyMap( map );
+
+  if( mImpl->mCustomShader )
+  {
+    mImpl->mCustomShader->CreatePropertyMap( map );
+  }
+
+  //map.Insert( DevelVisual::Property::DEPTH_INDEX, mImpl->mDepthIndex );
+  //map.Insert( DevelVisual::Property::ENABLED, (bool) mImpl->mRenderer );
+}
+
+
 void Visual::Base::EnablePreMultipliedAlpha( bool preMultipled )
 {
   if( preMultipled )
index e7d8ddd..15b2539 100644 (file)
@@ -131,6 +131,16 @@ public:
   void CreatePropertyMap( Property::Map& map ) const;
 
   /**
+   * @brief Create a property map containing per-instance visual properties.
+   *
+   * This will enable creation of new visuals on control state change with
+   * any alternative style properties and the relevant instance properties
+   * (e.g. for image visual, the desired size, and for text visual, the actual text).
+   * @param[in] map The property map into which to write
+   */
+  void CreateInstancePropertyMap( Property::Map& map ) const;
+
+  /**
    * @brief Set whether the Pre-multiplied Alpha Blending is required
    *
    * @param[in] preMultipled whether alpha is pre-multiplied.
@@ -222,6 +232,15 @@ protected:
   virtual void DoCreatePropertyMap( Property::Map& map ) const = 0;
 
   /**
+   * @brief Called by CreateInstancePropertyMap() allowing derived
+   * classes to store instanced data (separate to styled data) that
+   * needs copying between visuals on state change.
+   *
+   * @param[out] map The visual property map
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const = 0;
+
+  /**
    * @brief Called by SetProperties() allowing sub classes to set their properties
    *
    * @param[in] propertyMap The properties for the requested Visual object.
index 764ba27..990b25f 100644 (file)
@@ -153,6 +153,11 @@ void WireframeVisual::DoCreatePropertyMap( Property::Map& map ) const
   }
 }
 
+void WireframeVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
 void WireframeVisual::DoSetProperties( const Property::Map& propertyMap )
 {
   Property::Value* mixValue = propertyMap.Find( Toolkit::DevelVisual::Property::MIX_COLOR, MIX_COLOR );
index f446806..9edeca8 100644 (file)
@@ -109,6 +109,11 @@ protected: // from Visual::Base
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
   /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const;
+
+  /**
    * @copydoc Visual::Base::DoSetProperties()
    */
   virtual void DoSetProperties( const Property::Map& propertyMap );
index e77c28b..c89ae0c 100644 (file)
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
@@ -535,13 +537,233 @@ public:
     return value;
   }
 
-  void SetState( DevelControl::State state, bool withTransitions=true )
+
+  void CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
+  {
+    for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
+    {
+      if( (*iter)->visual )
+      {
+        Property::Map instanceMap;
+        Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
+        instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
+      }
+    }
+  }
+
+  template<typename T>
+  void Remove( Dictionary<T>& keyValues, const std::string& name )
+  {
+    keyValues.Remove(name);
+  }
+
+  void Remove( DictionaryKeys& keys, const std::string& name )
+  {
+    DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name );
+    if( iter != keys.end())
+    {
+      keys.erase(iter);
+    }
+  }
+
+  void FindChangableVisuals( Dictionary<Property::Map>& stateVisualsToAdd,
+                             Dictionary<Property::Map>& stateVisualsToChange,
+                             DictionaryKeys& stateVisualsToRemove)
+  {
+    DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
+
+    for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
+         iter != copyOfStateVisualsToRemove.end(); ++iter )
+    {
+      const std::string& visualName = (*iter);
+      Property::Map* toMap = stateVisualsToAdd.Find( visualName );
+      if( toMap )
+      {
+        stateVisualsToChange.Add( visualName, *toMap );
+        stateVisualsToAdd.Remove( visualName );
+        Remove( stateVisualsToRemove, visualName );
+      }
+    }
+  }
+
+  void RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
+  {
+    Actor self( mControlImpl.Self() );
+
+    for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
+          visualIter != visuals.End(); ++visualIter )
+    {
+      Toolkit::Visual::Base visual = (*visualIter)->visual;
+      if( visual && visual.GetName() == visualName )
+      {
+        Toolkit::GetImplementation(visual).SetOffStage( self );
+        (*visualIter)->visual.Reset();
+        visuals.Erase( visualIter );
+        break;
+      }
+    }
+  }
+
+  void RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
+  {
+    Actor self( mControlImpl.Self() );
+    for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
+    {
+      const std::string visualName = *iter;
+      RemoveVisual( visuals, visualName );
+    }
+  }
+
+  Toolkit::Visual::Type GetVisualTypeFromMap( const Property::Map& map )
+  {
+    Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE  );
+    Toolkit::Visual::Type type = Toolkit::Visual::IMAGE;
+    if( typeValue )
+    {
+      Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type );
+    }
+    return type;
+  }
+
+  /**
+   * Go through the list of visuals that are common to both states.
+   * If they are different types, or are both image types with different
+   * URLs, then the existing visual needs moving and the new visual creating
+   */
+  void RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
+                               Dictionary<Property::Map>& instancedProperties )
+  {
+    Dali::CustomActor handle( mControlImpl.GetOwner() );
+    for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
+         iter != stateVisualsToChange.End(); ++iter )
+    {
+      const std::string& visualName = (*iter).key;
+      const Property::Map& toMap = (*iter).entry;
+
+      // is it a candidate for re-creation?
+      bool recreate = false;
+
+      Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
+      if( visual )
+      {
+        Property::Map fromMap;
+        visual.CreatePropertyMap( fromMap );
+
+        Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap );
+        Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap );
+
+        if( fromType != toType )
+        {
+          recreate = true;
+        }
+        else
+        {
+          if( fromType == Toolkit::Visual::IMAGE )
+          {
+            Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+            Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+
+            if( fromUrl && toUrl )
+            {
+              std::string fromUrlString;
+              std::string toUrlString;
+              fromUrl->Get(fromUrlString);
+              toUrl->Get(toUrlString);
+
+              if( fromUrlString != toUrlString )
+              {
+                recreate = true;
+              }
+            }
+          }
+        }
+
+        const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
+        if( recreate || instancedMap )
+        {
+          RemoveVisual( mVisuals, visualName );
+          Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+        }
+        else
+        {
+          // @todo check to see if we can apply toMap without recreating the visual
+          // e.g. by setting only animatable properties
+          // For now, recreate all visuals, but merge in instance data.
+          RemoveVisual( mVisuals, visualName );
+          Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+        }
+      }
+    }
+  }
+
+  void ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
+  {
+    // Collect all old visual names
+    DictionaryKeys stateVisualsToRemove;
+    if( oldState )
+    {
+      oldState->visuals.GetKeys( stateVisualsToRemove );
+      if( ! subState.empty() )
+      {
+        const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
+        if( oldSubState )
+        {
+          DictionaryKeys subStateVisualsToRemove;
+          (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
+          Merge( stateVisualsToRemove, subStateVisualsToRemove );
+        }
+      }
+    }
+
+    // Collect all new visual properties
+    Dictionary<Property::Map> stateVisualsToAdd;
+    if( newState )
+    {
+      stateVisualsToAdd = newState->visuals;
+      if( ! subState.empty() )
+      {
+        const StylePtr* newSubState = newState->subStates.FindConst(subState);
+        if( newSubState )
+        {
+          stateVisualsToAdd.Merge( (*newSubState)->visuals );
+        }
+      }
+    }
+
+    // If a name is in both add/remove, move it to change list.
+    Dictionary<Property::Map> stateVisualsToChange;
+    FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
+
+    // Copy instanced properties (e.g. text label) of current visuals
+    Dictionary<Property::Map> instancedProperties;
+    CopyInstancedProperties( mVisuals, instancedProperties );
+
+    // For each visual in remove list, remove from mVisuals
+    RemoveVisuals( mVisuals, stateVisualsToRemove );
+
+    // For each visual in add list, create and add to mVisuals
+    Dali::CustomActor handle( mControlImpl.GetOwner() );
+    Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
+
+    // For each visual in change list, if it requires a new visual,
+    // remove old visual, create and add to mVisuals
+    RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
+  }
+
+  void SetState( DevelControl::State newState, bool withTransitions=true )
   {
-    if( mState != state )
+    DevelControl::State oldState = mState;
+    Dali::CustomActor handle( mControlImpl.GetOwner() );
+    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
+                  (mState == DevelControl::NORMAL ? "NORMAL" :(
+                    mState == DevelControl::FOCUSED ?"FOCUSED" : (
+                      mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
+
+    if( mState != newState )
     {
       // If mState was Disabled, and new state is Focused, should probably
       // store that fact, e.g. in another property that FocusManager can access.
-      mState = state;
+      mState = newState;
 
       // Trigger state change and transitions
       // Apply new style, if stylemanager is available
@@ -549,15 +771,19 @@ public:
       if( styleManager )
       {
         const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+
         if( stylePtr )
         {
-          for( int i=mVisuals.Count()-1; i >= 0; i-- )
+          std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
+          std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
+
+          const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
+          const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
+          if( oldStateStyle && newStateStyle )
           {
-            mControlImpl.UnregisterVisual( mVisuals[i]->index );
+            // Only change if both state styles exist
+            ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
           }
-
-          Dali::CustomActor handle( mControlImpl.GetOwner() );
-          stylePtr->ApplyVisualsAndPropertiesRecursively( handle );
         }
       }
     }
@@ -584,30 +810,12 @@ public:
           {
             StylePtr stateStyle(*state);
 
-            // Unregister existing visuals of this substate
-            const StylePtr* subState = stateStyle->subStates.Find( mSubStateName );
-            if( subState )
-            {
-              StylePtr subStateStyle(*subState);
-
-              for( Dictionary<Property::Map>::iterator iter = subStateStyle->visuals.Begin(); iter != subStateStyle->visuals.End(); ++iter )
-              {
-                const std::string& visualName = (*iter).key;
-                Dali::Property::Index index = handle.GetPropertyIndex( visualName );
-                if( index != Property::INVALID_INDEX )
-                {
-                  mControlImpl.UnregisterVisual( index );
-                }
-              }
-            }
-
-            // Register visuals of the new substate
-            const StylePtr* newSubState = stateStyle->subStates.Find( subStateName );
-            if( newSubState )
+            const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
+            const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
+            if( oldStateStyle && newStateStyle )
             {
-              StylePtr newSubStateStyle(*newSubState);
-              newSubStateStyle->ApplyVisuals( handle );
-              newSubStateStyle->ApplyProperties( handle );
+              std::string empty;
+              ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
             }
           }
         }