Added an example which shows a layout containing animating contact cards 66/93766/16
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 25 Oct 2016 20:36:06 +0000 (21:36 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 9 Nov 2016 16:19:46 +0000 (08:19 -0800)
Change-Id: Ic59f2e05275694ed1730628b9a1ac4950a759e3f

29 files changed:
.gitignore
build/tizen/CMakeLists.txt
com.samsung.dali-demo.xml
demo/dali-demo.cpp
examples/contact-cards/README.md [new file with mode: 0644]
examples/contact-cards/clipped-image.cpp [new file with mode: 0644]
examples/contact-cards/clipped-image.h [new file with mode: 0644]
examples/contact-cards/contact-card-layout-info.h [new file with mode: 0644]
examples/contact-cards/contact-card-layouter.cpp [new file with mode: 0644]
examples/contact-cards/contact-card-layouter.h [new file with mode: 0644]
examples/contact-cards/contact-card.cpp [new file with mode: 0644]
examples/contact-cards/contact-card.h [new file with mode: 0644]
examples/contact-cards/contact-cards-example.cpp [new file with mode: 0644]
examples/contact-cards/contact-data.cpp [new file with mode: 0644]
examples/contact-cards/contact-data.h [new file with mode: 0644]
resources/po/as.po
resources/po/de.po
resources/po/en_GB.po
resources/po/en_US.po
resources/po/es.po
resources/po/fi.po
resources/po/ko.po
resources/po/ml.po
resources/po/ur.po
resources/po/zn_CH.po
resources/style/.gitignore
resources/style/contact-cards-example-theme.json.in [new file with mode: 0644]
resources/style/mobile/contact-cards-example-theme.json.in [new file with mode: 0644]
shared/dali-demo-strings.h

index 156dc317c99a453a01547374ef96640df61343c5..c714b70dca52236cfb1ef793b88f41c3425e7fef 100644 (file)
@@ -39,3 +39,7 @@ dali-builder
 demo-theme.json
 simple-image-wall.js
 /shared/resources-location.cpp
+/build/tizen/documentation.list
+/debugfiles.list
+/debuglinks.list
+/debugsources.list
index 575f2b6aedff5723f903e96ee3e679109c943fca..1f119ad92468e773d05636c10f7f648aa213ab1e 100644 (file)
@@ -93,6 +93,7 @@ CONFIGURE_FILE( resources-location.in ${DEMO_SHARED}/resources-location.cpp )
 
 #Replace @DEMO_STYLE_IMAGE_DIR@ in following files
 CONFIGURE_FILE( ${LOCAL_STYLE_DIR}/demo-theme.json.in ${LOCAL_STYLE_DIR}/demo-theme.json )
+CONFIGURE_FILE( ${LOCAL_STYLE_DIR}/contact-cards-example-theme.json.in ${LOCAL_STYLE_DIR}/contact-cards-example-theme.json )
 CONFIGURE_FILE( ${LOCAL_STYLE_DIR}/style-example-theme-one.json.in ${LOCAL_STYLE_DIR}/style-example-theme-one.json )
 CONFIGURE_FILE( ${LOCAL_STYLE_DIR}/style-example-theme-two.json.in ${LOCAL_STYLE_DIR}/style-example-theme-two.json )
 CONFIGURE_FILE( ${LOCAL_STYLE_DIR}/style-example-theme-three.json.in ${LOCAL_STYLE_DIR}/style-example-theme-three.json )
index fb4f507b621dd9c1f5452db8b4d0158b5ee4eec0..14e92da66773242a0313631516119b95eb9471cc 100644 (file)
        <ui-application appid="progress-bar.example" exec="/usr/apps/com.samsung.dali-demo/bin/progress-bar.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
                <label>Progress Bar</label>
        </ui-application>
+       <ui-application appid="contact-cards.example" exec="/usr/apps/com.samsung.dali-demo/bin/contact-cards.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
+               <label>Contact Cards</label>
+       </ui-application>
 </manifest>
index b39b0702cb5f9f8d22638736599895b939b58df3..8c8142aad9eba6bb729ee7794d8771ac9a8a15af 100644 (file)
@@ -83,6 +83,7 @@ int DALI_EXPORT_API main(int argc, char **argv)
   demo.AddExample(Example("styling.example", DALI_DEMO_STR_TITLE_STYLING));
   demo.AddExample(Example("sparkle.example", DALI_DEMO_STR_TITLE_SPARKLE));
   demo.AddExample(Example("progress-bar.example", DALI_DEMO_STR_TITLE_PROGRESS_BAR));
+  demo.AddExample(Example("contact-cards.example", DALI_DEMO_STR_TITLE_CONTACT_CARDS));
 
   demo.SortAlphabetically( true );
 
diff --git a/examples/contact-cards/README.md b/examples/contact-cards/README.md
new file mode 100644 (file)
index 0000000..ef2f645
--- /dev/null
@@ -0,0 +1,2 @@
+Please use contact-cards-example.cpp as your start point.
+The ContactCardController class has a brief explanation regarding what this example does and all the classes used in this example.
diff --git a/examples/contact-cards/clipped-image.cpp b/examples/contact-cards/clipped-image.cpp
new file mode 100644 (file)
index 0000000..c27a5f6
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include "clipped-image.h"
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/dali-toolkit.h>
+
+namespace ClippedImage
+{
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+
+const char * const DELTA_PROPERTY_NAME( "uDelta" ); ///< Name of uniform used to mix the Circle and Quad geometries.
+
+/**
+ * @brief This vertex-shader mixes in the quad and circle geometry depending on the value of uDelta.
+ *
+ * uDelta is used to mix in the Circle and the Quad positions.
+ * If uDelta is 0.0f, then the circle position is adopted and if it is 1.0f, then the quad position is adopted.
+ */
+const char * VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2  aPositionCircle;\n
+  attribute mediump vec2  aPositionQuad;\n
+  uniform   mediump float uDelta;
+  uniform mediump mat4    uMvpMatrix;\n
+  uniform mediump vec3    uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(mix(aPositionCircle,aPositionQuad,uDelta), 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+/**
+ * @brief This fragment-shader does not output anything. It's for a control which is just going to clip as specified in the vertex shader.
+ */
+const char * FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  void main()\n
+  {\n
+    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n
+  }\n
+);
+
+/**
+ * @brief Creates the shader required for the clipped image
+ * @return A reference to a static handle to a shader object (only created when first called).
+ */
+Shader& CreateShader()
+{
+  // Only need to create it once
+  // The issue with using a static is that the shader will only get destroyed at application destruction.
+  // This is OK for a simple use cases such as this example, but for more polished applications, the shader creation/destruction needs to
+  // be managed by the application writer.
+  static Shader shader;
+
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+  }
+
+  return shader;
+}
+
+/**
+ * @brief Creates the geometry required for the clipped image
+ * @return A reference to a static handle to a geometry object (only created when first called).
+ */
+Geometry& CreateGeometry()
+{
+  // Only need to create it once
+  // The issue with using a static is that the geometry will only get destroyed at application destruction.
+  // This is OK for a simple use cases such as this example, but for more polished applications, the geometry creation/destruction needs to
+  // be managed by the application writer.
+  static Geometry geometry;
+
+  if ( !geometry )
+  {
+    const int vertexCount = 34; // Needs to be 4n plus 2 where n is a positive integer above 4
+
+    // Create the circle geometry
+
+    // Radius is bound to actor's dimensions so this should not be increased.
+    // If a bigger circle is required then the actor size should be increased.
+    const float radius = 0.5f;
+    const Vector2 center = Vector2::ZERO;
+
+    // Create a buffer for vertex data
+    Vector2 circleBuffer[vertexCount];
+    int idx = 0;
+
+    // Center vertex for triangle fan
+    circleBuffer[ idx++ ] = center;
+
+    // Outer vertices of the circle
+    const int outerVertexCount = vertexCount - 1;
+
+    for ( int i = 0; i < outerVertexCount; ++i )
+    {
+      const float percent = ( i / static_cast< float >( outerVertexCount - 1 ) );
+      const float rad = percent * 2.0f * Math::PI;
+
+      // Vertex position
+      Vector2 outer;
+      outer.x = center.x + radius * cos( rad );
+      outer.y = center.y + radius * sin( rad );
+
+      circleBuffer[ idx++ ] = outer;
+    }
+
+    Property::Map circleVertexFormat;
+    circleVertexFormat["aPositionCircle"] = Property::VECTOR2;
+    PropertyBuffer circleVertices = PropertyBuffer::New( circleVertexFormat );
+    circleVertices.SetData( circleBuffer, vertexCount );
+
+    // Create the Quad Geometry
+    Vector2 quadBuffer[vertexCount];
+    idx = 0;
+    quadBuffer[ idx++ ]  = center;
+
+    const size_t vertsPerSide = ( vertexCount - 2 ) / 4;
+    Vector2 outer( 0.5f, 0.0f );
+    quadBuffer[ idx++ ]  = outer;
+    float incrementPerBuffer = 1.0f / static_cast< float >( vertsPerSide );
+
+    for( size_t i = 0; i < vertsPerSide && outer.y < 0.5f; ++i )
+    {
+      outer.y += incrementPerBuffer;
+      quadBuffer[ idx++ ] = outer;
+    }
+
+    for( size_t i = 0; i < vertsPerSide && outer.x > -0.5f; ++i )
+    {
+      outer.x -= incrementPerBuffer;
+      quadBuffer[ idx++ ] = outer;
+    }
+
+    for( size_t i = 0; i < vertsPerSide && outer.y > -0.5f; ++i )
+    {
+      outer.y -= incrementPerBuffer;
+      quadBuffer[ idx++ ] = outer;
+    }
+
+    for( size_t i = 0; i < vertsPerSide && outer.x < 0.5f; ++i )
+    {
+      outer.x += incrementPerBuffer;
+      quadBuffer[ idx++ ] = outer;
+    }
+
+    for( size_t i = 0; i < vertsPerSide && outer.y < 0.0f; ++i )
+    {
+      outer.y += incrementPerBuffer;
+      quadBuffer[ idx++ ] = outer;
+    }
+
+    Property::Map vertexFormat;
+    vertexFormat["aPositionQuad"] = Property::VECTOR2;
+    PropertyBuffer quadVertices2 = PropertyBuffer::New( vertexFormat );
+    quadVertices2.SetData( quadBuffer, vertexCount );
+
+    // Create the geometry object itself
+    geometry = Geometry::New();
+    geometry.AddVertexBuffer( circleVertices );
+    geometry.AddVertexBuffer( quadVertices2 );
+    geometry.SetType( Geometry::TRIANGLE_FAN );
+  }
+
+  return geometry;
+}
+
+} // unnamed namespace
+
+const float CIRCLE_GEOMETRY = 0.0f;
+const float QUAD_GEOMETRY = 1.0f;
+
+Dali::Toolkit::Control Create( const std::string& imagePath, Property::Index& propertyIndex )
+{
+  // Create a control which whose geometry will be morphed between a circle and a quad
+  Control clippedImage = Control::New();
+  clippedImage.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  // Create the required renderer and add to the clipped image control
+  Renderer renderer = Renderer::New( CreateGeometry(), CreateShader() );
+  renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  clippedImage.AddRenderer( renderer );
+
+  // Register the property on the clipped image control which will allow animations between a circle and a quad
+  propertyIndex = clippedImage.RegisterProperty( DELTA_PROPERTY_NAME, 0.0f );
+
+  // Add the actual image to the control
+  Control image = ImageView::New( imagePath );
+  image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  image.SetParentOrigin( ParentOrigin::CENTER );
+  image.SetAnchorPoint( AnchorPoint::CENTER );
+  clippedImage.Add( image );
+
+  return clippedImage;
+}
+
+} // namespace ClippedImage
diff --git a/examples/contact-cards/clipped-image.h b/examples/contact-cards/clipped-image.h
new file mode 100644 (file)
index 0000000..edfd86a
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef CLIPPED_IMAGE_H
+#define CLIPPED_IMAGE_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali-toolkit/public-api/controls/control.h>
+
+/**
+ * @brief This namespace provides a helper function to create a control that clips an image either as a quad or a circle.
+ *
+ * The CIRCLE_GEOMETRY and QUAD_GEOMETRY constants can be used to set or animate to the different clipping geometries.
+ */
+namespace ClippedImage
+{
+
+extern const float CIRCLE_GEOMETRY; ///< Setting or animating the returned propertyIndex in Create() to this value will provide a circle geometry on the image @see Create
+extern const float QUAD_GEOMETRY; ///< Setting or animating the returned propertyIndex in Create() to this value will provide a quad geometry on the image @see Create
+
+/**
+ * @brief Creates a clipping image whose geometry (i.e. clip area) can be morphed between a circle and a quad by animating the propertyIndex out parameter.
+ *
+ * The propertyIndex parameter can be set or animated to CIRCLE_GEOMETRY or QUAD_GEOMETRY depending on the type of clipping required.
+ * If set to a value between these two constants, then the resulting geometry will be somewhere in between a circle and a quad.
+ *
+ * @param[in]   imagePath      The path to the image to show.
+ * @param[out]  propertyIndex  Gets set with the property index which the caller can animate using the CIRCLE_GEOMETRY & QUAD_GEOMETRY values.
+ * @return The image-mesh control
+ */
+Dali::Toolkit::Control Create( const std::string& imagePath, Dali::Property::Index& propertyIndex );
+
+} // namespace ClippedImage
+
+#endif // CLIPPED_IMAGE_H
diff --git a/examples/contact-cards/contact-card-layout-info.h b/examples/contact-cards/contact-card-layout-info.h
new file mode 100644 (file)
index 0000000..68e3f20
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef CONTACT_CARD_LAYOUT_INFO_H
+#define CONTACT_CARD_LAYOUT_INFO_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector2.h>
+
+/**
+ * @brief This is the common data that is used by all contact cards.
+ *
+ * In this context, "unfolded" means when all the details, including the name, address and image are shown.
+ * In this scenario, the control takes up most of the screen and a header is also shown.
+ *
+ * When the contact card is "folded", this means when only brief information is shown to the user, i.e. the image and name.
+ * In this scenario, the control is small and there should be several of these contact cards visible on the screen.
+ */
+struct ContactCardLayoutInfo
+{
+  Dali::Vector2 unfoldedPosition; ///< The position of the entire contact card when all details (unfolded) are shown
+  Dali::Vector2 unfoldedSize;     ///< The size of the entire contact card when all details (unfolded) are shown
+  Dali::Vector2 foldedSize;       ///< The size of each contact card when only the brief information is shown (folded)
+
+  Dali::Vector2 padding; ///< The default padding to use throughout
+
+  Dali::Vector2 headerSize;             ///< The size of the header area (only shown when unfolded)
+  Dali::Vector2 headerFoldedPosition;   ///< The position of the header area when folded - required for animation purposes only as it's actually clipped
+  Dali::Vector2 headerUnfoldedPosition; ///< The position of the header area when unfolded
+
+  Dali::Vector2 imageSize;             ///< The size of the image
+  Dali::Vector2 imageFoldedPosition;   ///< The position of the image when folded
+  Dali::Vector2 imageUnfoldedPosition; ///< The position of the image when unfolded
+
+  Dali::Vector2 textFoldedPosition;   ///< The position of the text when folded
+  Dali::Vector2 textUnfoldedPosition; ///< The position of the text when unfolded
+};
+
+#endif // CONTACT_CARD_LAYOUT_INFO_H
+
diff --git a/examples/contact-cards/contact-card-layouter.cpp b/examples/contact-cards/contact-card-layouter.cpp
new file mode 100644 (file)
index 0000000..c638f83
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "contact-card-layouter.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/stage.h>
+
+// INTERNAL INCLUDES
+#include "contact-card.h"
+
+using namespace Dali;
+
+namespace
+{
+const float DEFAULT_PADDING = 25.0f;
+
+const float MINIMUM_ITEMS_PER_ROW_OR_COLUMN( 3.0f );
+
+const float HEADER_HEIGHT_TO_UNFOLDED_SIZE_RATIO( 0.1f );
+const Vector2 HEADER_FOLDED_POSITION_AS_RATIO_OF_SIZE( -0.05f, -1.5f );
+const Vector2 HEADER_UNFOLDED_POSITION( Vector2::ZERO );
+
+const float IMAGE_SIZE_AS_RATIO_TO_FOLDED_SIZE( 0.5f );
+const Vector2 IMAGE_FOLDED_POSITION_AS_RATIO_OF_SIZE( 0.5f, 0.25f );
+
+const float FOLDED_TEXT_POSITION_AS_RATIO_OF_IMAGE_SIZE( 1.01f );
+} // unnamed namespace
+
+ContactCardLayouter::ContactCardLayouter()
+: mContactCardLayoutInfo(),
+  mContactCards(),
+  mLastPosition(),
+  mPositionIncrementer(),
+  mItemsPerRow( 0 ),
+  mInitialized( false )
+{
+}
+
+ContactCardLayouter::~ContactCardLayouter()
+{
+  // Nothing to do as ContactCardContainer uses intrusive pointers so they will be automatically deleted
+}
+
+void ContactCardLayouter::AddContact( const std::string& contactName, const std::string& contactAddress, const std::string& imagePath )
+{
+  if( ! mInitialized )
+  {
+    // Set up the common layouting info shared between all contact cards when first called
+
+    mContactCardLayoutInfo.unfoldedPosition = mContactCardLayoutInfo.padding = Vector2( DEFAULT_PADDING, DEFAULT_PADDING );
+    mContactCardLayoutInfo.unfoldedSize = Stage::GetCurrent().GetSize() - mContactCardLayoutInfo.padding * ( MINIMUM_ITEMS_PER_ROW_OR_COLUMN - 1.0f );
+
+    // Calculate the size of the folded card (use the minimum of width/height as size)
+    mContactCardLayoutInfo.foldedSize = ( mContactCardLayoutInfo.unfoldedSize - ( mContactCardLayoutInfo.padding * ( MINIMUM_ITEMS_PER_ROW_OR_COLUMN - 1.0f ) ) ) / MINIMUM_ITEMS_PER_ROW_OR_COLUMN;
+    mContactCardLayoutInfo.foldedSize.width = mContactCardLayoutInfo.foldedSize.height = std::min( mContactCardLayoutInfo.foldedSize.width, mContactCardLayoutInfo.foldedSize.height );
+
+    // Set the size and positions of the header
+    mContactCardLayoutInfo.headerSize.width = mContactCardLayoutInfo.unfoldedSize.width;
+    mContactCardLayoutInfo.headerSize.height = mContactCardLayoutInfo.unfoldedSize.height * HEADER_HEIGHT_TO_UNFOLDED_SIZE_RATIO;
+    mContactCardLayoutInfo.headerFoldedPosition = mContactCardLayoutInfo.headerSize * HEADER_FOLDED_POSITION_AS_RATIO_OF_SIZE;
+    mContactCardLayoutInfo.headerUnfoldedPosition = HEADER_UNFOLDED_POSITION;
+
+    // Set the image size and positions
+    mContactCardLayoutInfo.imageSize = mContactCardLayoutInfo.foldedSize * IMAGE_SIZE_AS_RATIO_TO_FOLDED_SIZE;
+    mContactCardLayoutInfo.imageFoldedPosition = mContactCardLayoutInfo.imageSize * IMAGE_FOLDED_POSITION_AS_RATIO_OF_SIZE;
+    mContactCardLayoutInfo.imageUnfoldedPosition.x = mContactCardLayoutInfo.padding.width;
+    mContactCardLayoutInfo.imageUnfoldedPosition.y = mContactCardLayoutInfo.headerSize.height + mContactCardLayoutInfo.padding.height;
+
+    // Set the positions of the contact name
+    mContactCardLayoutInfo.textFoldedPosition.x = 0.0f;
+    mContactCardLayoutInfo.textFoldedPosition.y = mContactCardLayoutInfo.imageFoldedPosition.x + mContactCardLayoutInfo.imageSize.height * FOLDED_TEXT_POSITION_AS_RATIO_OF_IMAGE_SIZE;
+    mContactCardLayoutInfo.textUnfoldedPosition.x = mContactCardLayoutInfo.padding.width;
+    mContactCardLayoutInfo.textUnfoldedPosition.y = mContactCardLayoutInfo.imageUnfoldedPosition.y + mContactCardLayoutInfo.imageSize.height + mContactCardLayoutInfo.padding.height;
+
+    // Figure out the positions of the contact cards
+    mItemsPerRow = ( mContactCardLayoutInfo.unfoldedSize.width + mContactCardLayoutInfo.padding.width ) / ( mContactCardLayoutInfo.foldedSize.width + mContactCardLayoutInfo.padding.width );
+    mLastPosition = mContactCardLayoutInfo.unfoldedPosition;
+    mPositionIncrementer.x = mContactCardLayoutInfo.foldedSize.width + mContactCardLayoutInfo.padding.width;
+    mPositionIncrementer.y = mContactCardLayoutInfo.foldedSize.height + mContactCardLayoutInfo.padding.height;
+
+    mInitialized = true;
+  }
+
+  // Create a new contact card and add to our container
+  mContactCards.push_back( new ContactCard( mContactCardLayoutInfo, contactName, contactAddress, imagePath, NextCardPosition() ) );
+}
+
+const Vector2& ContactCardLayouter::NextCardPosition()
+{
+  size_t currentNumOfCards = mContactCards.size();
+
+  if( currentNumOfCards )
+  {
+    if( currentNumOfCards % mItemsPerRow )
+    {
+      mLastPosition.x += mPositionIncrementer.x;
+    }
+    else // go to the next row
+    {
+      mLastPosition.x = mContactCardLayoutInfo.unfoldedPosition.x;
+      mLastPosition.y += mPositionIncrementer.y;
+    }
+  }
+  return mLastPosition;
+}
diff --git a/examples/contact-cards/contact-card-layouter.h b/examples/contact-cards/contact-card-layouter.h
new file mode 100644 (file)
index 0000000..ed4d17b
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef CONTACT_CARD_LAYOUTER_H
+#define CONTACT_CARD_LAYOUTER_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <vector>
+#include <string>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include "contact-card-layout-info.h"
+
+class ContactCard;
+
+/**
+ * @brief This class lays out contact cards on the screen appropriately.
+ *
+ * The contact cards are added to the stage directly and it uses the stage size to figure out exactly how to layout them.
+ * It supports a minimum of 3 items on each row or column.
+ *
+ * Relayouting is not supported.
+ */
+class ContactCardLayouter
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  ContactCardLayouter();
+
+  /**
+   * @brief Destructor.
+   */
+  ~ContactCardLayouter();
+
+  /**
+   * @brief Creates a contact card with the given information.
+   * @param[in]  contactName     The name of the contact to display.
+   * @param[in]  contactAddress  The address of the contact to display.
+   * @param[in]  imagePath       The path to the image to display.
+   */
+  void AddContact( const std::string& contactName, const std::string& contactAddress, const std::string& imagePath );
+
+private:
+
+  /**
+   * @brief Calculates the next position of the contact card that's about to be added to our container.
+   * @return A reference to the next position.
+   */
+  const Dali::Vector2& NextCardPosition();
+
+  ContactCardLayoutInfo mContactCardLayoutInfo; ///< The common layouting information used by all contact cards. Set up when AddContact is first called.
+
+  typedef Dali::IntrusivePtr< ContactCard > ContactCardPtr; ///< Better than raw pointers as these are ref counted and the memory is released when the count reduces to 0.
+  typedef std::vector< ContactCardPtr > ContactCardContainer;
+  ContactCardContainer mContactCards; ///< Contains all the contact cards.
+
+  Dali::Vector2 mLastPosition; ///< The last position a contact card was added.
+  Dali::Vector2 mPositionIncrementer; ///< Calculated once when AddContact is first called.
+  size_t mItemsPerRow; ///< Calculated once when AddContact is first called and stores the number of items we have in a row.
+
+  bool mInitialized; ///< Whether initialization has taken place or not.
+};
+
+
+
+#endif // CONTACT_CARD_LAYOUTER_H
diff --git a/examples/contact-cards/contact-card.cpp b/examples/contact-cards/contact-card.cpp
new file mode 100644 (file)
index 0000000..eb89a6c
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "contact-card.h"
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/dali-toolkit.h>
+
+// INTERNAL INCLUDES
+#include "contact-card-layout-info.h"
+#include "clipped-image.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+/*
+ * The constants below are used to create the following Unfold Animation.
+ *
+ * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
+ * |    |    |    |    |    |    |    |    |
+ * o-----------------------------------o   |  X Position Animation            ( 0ms To 360ms)
+ * |   o-----------------------------------o  Y Position Animation            (40ms To 400ms)
+ * o-----------------------------------o   |  Width Animation                 ( 0ms To 360ms)
+ * |   o-----------------------------------o  Height Animation                (40ms To 400ms)
+ * o-------o |    |    |    |    |    |    |  Fade out Name Text Animation    ( 0ms To  80ms)
+ * |       o-------o   |    |    |    |    |  Fade in Details Text Animation  (80ms To 160ms)
+ * o---------------o   |    |    |    |    |  Fade out other cards Animation  ( 0ms To 160ms)
+ * o---------------------------------------o  Mesh Morph Animation            ( 0ms To 400ms)
+ */
+const TimePeriod TIME_PERIOD_UNFOLD_X( 0.0f,  0.36f ); ///< Start at 0ms, duration 360ms
+const TimePeriod TIME_PERIOD_UNFOLD_Y( 0.04f, 0.36f ); ///< Start at 40ms, duration 360ms
+const TimePeriod TIME_PERIOD_UNFOLD_WIDTH( 0.0f,  0.36f ); ///< Start at 0ms, duration 360ms
+const TimePeriod TIME_PERIOD_UNFOLD_HEIGHT( 0.04f, 0.36f ); ///< Start at 40ms, duration 360ms
+const TimePeriod TIME_PERIOD_UNFOLD_NAME_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
+const TimePeriod TIME_PERIOD_UNFOLD_DETAIL_OPACITY( 0.08f, 0.08f ); ///< Start at 80ms, duration 80ms
+const TimePeriod TIME_PERIOD_UNFOLD_SIBLING_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
+const TimePeriod TIME_PERIOD_UNFOLD_MESH_MORPH( 0.0f, 0.4f ); ///< Start at 0ms, duration 400ms
+
+/*
+ * The constants below are used to create the following Fold Animation:
+ *
+ * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
+ * |    |    |    |    |    |    |    |    |
+ * |    |o---------------------------------o  X Position Animation            ( 64ms To 400ms)
+ * o---------------------------------o|    |  Y Position Animation            (  0ms To 336ms)
+ * |    |o---------------------------------o  Width Animation                 ( 64ms To 400ms)
+ * o---------------------------------o|    |  Height Animation                (  0ms To 336ms)
+ * |       o-------o   |    |    |    |    |  Fade in Name Text animation     ( 80ms To 160ms)
+ * o-------o |    |    |    |    |    |    |  Fade out Details Text animation (  0ms To  80ms)
+ * |    |    |    |    |    |    | o-------o  Fade in other cards animation   (320ms To 400ms)
+ * o---------------------------------------o  Morph Animation                 (  0ms To 400ms)
+ */
+const TimePeriod TIME_PERIOD_FOLD_X( 0.064f, 0.336f ); ///< Start at 64ms, duration 336ms
+const TimePeriod TIME_PERIOD_FOLD_Y( 0.0f, 0.336f ); ///< Start at 0ms, duration 336ms
+const TimePeriod TIME_PERIOD_FOLD_WIDTH( 0.064f, 0.336f ); ///< Start at 64ms, duration 336ms
+const TimePeriod TIME_PERIOD_FOLD_HEIGHT( 0.0f, 0.336f ); ///< Start at 0ms, duration 336ms
+const TimePeriod TIME_PERIOD_FOLD_NAME_OPACITY( 0.08f, 0.08f ); ///< Start at 80ms, duration 80ms
+const TimePeriod TIME_PERIOD_FOLD_DETAIL_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
+const TimePeriod TIME_PERIOD_FOLD_SIBLING_OPACITY( 0.32f, 0.08f ); ///< Start at 320ms, duration 80ms
+const TimePeriod TIME_PERIOD_FOLD_MESH_MORPH( 0.0f, 0.4f ); ///< Start at 0ms, duration 400ms
+
+AlphaFunction ALPHA_FUNCTION_UNFOLD( AlphaFunction::DEFAULT ); ///< Alpha function used for the Unfold Animation
+AlphaFunction ALPHA_FUNCTION_FOLD( AlphaFunction::EASE_IN_OUT ); ///< Alpha function used for the Fold Animation
+
+const Vector4 HEADER_COLOR( 231.0f/255.0f, 231.0f/255.0f, 231.0f/255.0f, 1.0f ); ///< The color of the header
+
+} // unnamed namespace
+
+ContactCard::ContactCard(
+    const ContactCardLayoutInfo& contactCardLayoutInfo,
+    const std::string& contactName,
+    const std::string& contactAddress,
+    const std::string& imagePath,
+    const Vector2& position )
+: mTapDetector(),
+  mContactCard(),
+  mHeader(),
+  mClippedImage(),
+  mNameText(),
+  mDetailText(),
+  mSlotDelegate( this ),
+  mContactCardLayoutInfo( contactCardLayoutInfo ),
+  foldedPosition( position ),
+  mClippedImagePropertyIndex( Property::INVALID_INDEX ),
+  mFolded( true )
+{
+  // Create a control which will be used for the background and to clip the contents
+  mContactCard = Control::New();
+  mContactCard.SetProperty( Control::Property::BACKGROUND,
+                            Property::Map().Add( Visual::Property::TYPE, Visual::COLOR )
+                                           .Add( ColorVisual::Property::MIX_COLOR, Color::WHITE ) );
+  mContactCard.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+  mContactCard.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mContactCard.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mContactCard.SetPosition( foldedPosition.x, foldedPosition.y );
+  mContactCard.SetSize( mContactCardLayoutInfo.foldedSize );
+  Stage::GetCurrent().Add( mContactCard );
+
+  // Create the header which will be shown only when the contact is unfolded
+  mHeader = Control::New();
+  mHeader.SetSize( mContactCardLayoutInfo.headerSize );
+  mHeader.SetProperty( Control::Property::BACKGROUND,
+                       Property::Map().Add( Visual::Property::TYPE, Visual::COLOR )
+                                      .Add( ColorVisual::Property::MIX_COLOR, HEADER_COLOR ) );
+  mHeader.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mHeader.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mHeader.SetPosition( mContactCardLayoutInfo.headerFoldedPosition.x, mContactCardLayoutInfo.headerFoldedPosition.y );
+
+  // Create a clipped image (whose clipping can be animated)
+  mClippedImage = ClippedImage::Create( imagePath, mClippedImagePropertyIndex );
+  mClippedImage.SetSize( mContactCardLayoutInfo.imageSize );
+  mClippedImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mClippedImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mClippedImage.SetPosition( mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y );
+  mContactCard.Add( mClippedImage );
+
+  // Add the text label for just the name
+  mNameText = TextLabel::New( contactName );
+  mNameText.SetStyleName( "ContactNameTextLabel" );
+  mNameText.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mNameText.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mNameText.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+  mNameText.SetPosition( mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y );
+  mContactCard.Add( mNameText );
+
+  // Create the detail text-label
+  std::string detailString( contactName );
+  detailString += "\n\n";
+  detailString += contactAddress;
+
+  mDetailText = TextLabel::New( detailString );
+  mDetailText.SetStyleName( "ContactDetailTextLabel" );
+  mDetailText.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mDetailText.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mDetailText.SetPosition( mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y );
+  mDetailText.SetSize( Vector2( mContactCardLayoutInfo.unfoldedSize.width - mContactCardLayoutInfo.textFoldedPosition.x * 2.0f, 0.0f ) );
+  mDetailText.SetOpacity( 0.0f );
+
+  // Attach tap detection to the overall clip control
+  mTapDetector = TapGestureDetector::New();
+  mTapDetector.Attach( mContactCard );
+  mTapDetector.DetectedSignal().Connect( mSlotDelegate, &ContactCard::OnTap );
+}
+
+ContactCard::~ContactCard()
+{
+  if( mContactCard )
+  {
+    mContactCard.Unparent();
+  }
+}
+
+void ContactCard::OnTap( Actor actor, const TapGesture& gesture )
+{
+  if( mFolded )
+  {
+    mContactCard.Add( mHeader );
+    mContactCard.Add( mDetailText );
+
+    // Animate the size of the control (and clipping area)
+    Animation animation = Animation::New( 0.0f ); // Overall duration is unimportant as superseded by TimePeriods set later
+    animation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.unfoldedPosition.x,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.unfoldedPosition.y,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ),  mContactCardLayoutInfo.unfoldedSize.width,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_WIDTH );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_HEIGHT ), mContactCardLayoutInfo.unfoldedSize.height, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_HEIGHT );
+
+    // Animate the header area into position
+    animation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    animation.AnimateTo( Property( mHeader, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.headerUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+
+    // Animate the clipped image into the unfolded position and into a quad
+    animation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.imageUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    animation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.imageUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+    animation.AnimateTo( Property( mClippedImage, mClippedImagePropertyIndex ), ClippedImage::QUAD_GEOMETRY, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_MESH_MORPH );
+
+    // Fade out the opacity of the name, and animate into the unfolded position
+    animation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_NAME_OPACITY );
+    animation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    animation.AnimateTo( Property( mNameText, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+
+    // Fade in the opacity of the detail, and animate into the unfolded position
+    animation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_DETAIL_OPACITY );
+    animation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    animation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+
+    // Fade out all the siblings
+    Actor parent = actor.GetParent();
+    for( size_t i = 0; i < parent.GetChildCount(); ++i )
+    {
+      Actor sibling = parent.GetChildAt( i );
+      if( sibling != actor )
+      {
+        animation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_SIBLING_OPACITY );
+        sibling.SetSensitive( false );
+      }
+    }
+
+    animation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
+    animation.Play();
+  }
+  else
+  {
+    mContactCard.Add( mNameText );
+
+    // Animate the size of the control (and clipping area)
+    Animation animation = Animation::New( 0.0f ); // Overall duration is unimportant as superseded by TimePeriods set later
+    animation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ),  foldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ),  foldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ),  mContactCardLayoutInfo.foldedSize.width,  ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_WIDTH );
+    animation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_HEIGHT ), mContactCardLayoutInfo.foldedSize.height, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_HEIGHT );
+
+    // Animate the header area out of position
+    animation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    animation.AnimateTo( Property( mHeader, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.headerFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+
+    // Animate the clipped image into the folded position and into a circle
+    animation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.imageFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    animation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.imageFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+    animation.AnimateTo( Property( mClippedImage, mClippedImagePropertyIndex ), ClippedImage::CIRCLE_GEOMETRY, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_MESH_MORPH );
+
+    // Fade in the opacity of the name, and animate into the folded position
+    animation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_NAME_OPACITY );
+    animation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    animation.AnimateTo( Property( mNameText, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+
+    // Fade out the opacity of the detail, and animate into the folded position
+    animation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_DETAIL_OPACITY );
+    animation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    animation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+
+    // Slowly fade in all the siblings
+    Actor parent = actor.GetParent();
+    for( size_t i = 0; i < parent.GetChildCount(); ++i )
+    {
+      Actor sibling = parent.GetChildAt( i );
+      if( sibling != actor )
+      {
+        animation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_SIBLING_OPACITY );
+        sibling.SetSensitive( true );
+      }
+    }
+
+    animation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
+    animation.Play();
+  }
+
+  mFolded = !mFolded;
+}
+
+void ContactCard::OnAnimationFinished( Dali::Animation& animation )
+{
+  if( mFolded )
+  {
+    mHeader.Unparent();
+    mDetailText.Unparent();
+  }
+  else
+  {
+    mNameText.Unparent();
+  }
+}
diff --git a/examples/contact-cards/contact-card.h b/examples/contact-cards/contact-card.h
new file mode 100644 (file)
index 0000000..043bfde
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef CONTACT_CARD_H
+#define CONTACT_CARD_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/events/tap-gesture-detector.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali-toolkit/public-api/controls/control.h>
+
+class ContactCardLayoutInfo;
+
+/**
+ * @brief Creates and sets up animations for a contact card
+ *
+ * Each contact card has two states, folded and unfolded.
+ * In this context, "unfolded" means when all the details, including the name, address and image are shown.
+ * In this scenario, the control takes up most of the screen.
+ *
+ * When the contact card is "folded", this means when only brief information is shown to the user, i.e. the image and name.
+ * In this scenario, the control is small and there should be several of these contact cards visible on the screen.
+ *
+ * The contact card creates several controls that it requires to appropriately display itself in both of these states.
+ */
+class ContactCard : public Dali::RefObject
+{
+public:
+
+  /**
+   * @brief Constructor.
+   *
+   * This will create all the controls and add them to the stage so should only be called after the init-signal from the Application has been received.
+   *
+   * @param[in]  contactCardLayoutInfo  Reference to the common data used by all contact cards.
+   * @param[in]  contactName            The name of the contact to display.
+   * @param[in]  contactAddress         The address of the contact to display.
+   * @param[in]  imagePath              The path to the image to display.
+   * @param[in]  position               The unique folded position of this particular contact-card.
+   */
+  ContactCard( const ContactCardLayoutInfo& contactCardLayoutInfo, const std::string& contactName, const std::string& contactAddress, const std::string& imagePath, const Dali::Vector2& position );
+
+private:
+
+  /**
+   * @brief Private Destructor. Will only be deleted when ref-count goes to 0.
+   *
+   * Unparent the created contact card (i.e. remove from stage).
+   */
+  ~ContactCard();
+
+  /**
+   * @brief Called when this contact card is tapped.
+   * @param[in] actor The tapped actor.
+   * @param[in] gesture The tap gesture.
+   */
+  void OnTap( Dali::Actor actor, const Dali::TapGesture& gesture );
+
+  /**
+   * @brief Called when the animation finishes.
+   * @param[in] animation The animation which has just finished.
+   */
+  void OnAnimationFinished( Dali::Animation& animation );
+
+  Dali::TapGestureDetector mTapDetector; ///< Used for tap detection.
+  Dali::Toolkit::Control mContactCard; ///< Used for the background and to clip the contents.
+  Dali::Toolkit::Control mHeader; ///< Header shown when unfolded.
+  Dali::Toolkit::Control mClippedImage; ///< The image representing the contact (whose clipping can be animated).
+  Dali::Toolkit::Control mNameText; ///< The text shown when folded.
+  Dali::Toolkit::Control mDetailText; ///< The text shown when unfolded.
+
+  Dali::SlotDelegate< ContactCard > mSlotDelegate; ///< Used to automatically disconnect our member functions from signals that this class connects to upon destruction. Can be used instead of inheriting from ConnectionTracker.
+
+  const ContactCardLayoutInfo& mContactCardLayoutInfo; ///< Reference to the common data used by all contact cards.
+  const Dali::Vector2 foldedPosition; ///< The unique position of this card when it is folded.
+  Dali::Property::Index mClippedImagePropertyIndex; ///< Index used to animate the clipping of mClippedImage.
+  bool mFolded; ///< Whether the contact card is folded or not.
+};
+
+#endif // CONTACT_CARD_H
diff --git a/examples/contact-cards/contact-cards-example.cpp b/examples/contact-cards/contact-cards-example.cpp
new file mode 100644 (file)
index 0000000..d9c4d57
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <vector>
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/key-event.h>
+
+// INTERNAL INCLUDES
+#include "contact-card-layouter.h"
+#include "contact-data.h"
+
+using namespace Dali;
+
+namespace
+{
+const Vector4 STAGE_COLOR( 211.0f / 255.0f, 211.0f / 255.0f, 211.0f / 255.0f, 1.0f ); ///< The color of the stage
+const char * const THEME_PATH( DEMO_STYLE_DIR "contact-cards-example-theme.json" ); ///< The theme used for this example
+} // unnamed namespace
+
+/**
+ * @brief Creates several contact cards that animate between a folded and unfolded state.
+ *
+ * This demonstrates how different animations can start and stop at different times within the same Animation function.
+ * Additionally, this also shows how to morph between two different geometries.
+ *
+ * ContactCardLayouter: This class is used to lay out the different contact cards on the screen.
+ *                      This takes stage size into account but does not support relayouting.
+ * ContactCard: This class represents each contact card on the screen.
+ *              Two animations are set up in this class which animate several properties with multiple start and stop times.
+ *              An overview of the two animations can be found in contact-card.cpp.
+ * ContactCardLayoutInfo: This is a structure to store common layout information and is created by the ContactCardLayouter and used by each ContactCard.
+ * ContactData: This namespace contains a table which has the contact information we use to populate the contact cards.
+ * ClippedImage: This namespace provides a helper function which creates an ImageView which is added to a control that has clipping.
+ *               This clipping comes in the form of a Circle or Quad.
+ *               The Vertex shader mixes in the Circle and Quad geometry depending on the value of a uniform float.
+ *               Animating this float between CIRCLE_GEOMETRY and QUAD_GEOMETRY is what enables the morphing between the two geometries.
+ */
+class ContactCardController : public ConnectionTracker // Inherit from ConnectionTracker so that our signals can be automatically disconnected upon our destruction.
+{
+public:
+
+  /**
+   * @brief Constructor.
+   * @param[in]  application A reference to the Application class.
+   */
+  ContactCardController( Application& application )
+  : mApplication( application )
+  {
+    // Connect to the Application's Init signal
+    mApplication.InitSignal().Connect( this, &ContactCardController::Create );
+  }
+
+private:
+
+  /**
+   * @brief Called to initialise the application content
+   * @param[in] application A reference to the Application class.
+   */
+  void Create( Application& application )
+  {
+    // Hide the indicator bar
+    application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
+
+    // Set the stage background color and connect to the stage's key signal to allow Back and Escape to exit.
+    Stage stage = Stage::GetCurrent();
+    stage.SetBackgroundColor( STAGE_COLOR );
+    stage.KeyEventSignal().Connect( this, &ContactCardController::OnKeyEvent );
+
+    // Add all the contacts to the layouter
+    for( size_t i = 0; i < ContactData::TABLE_SIZE; ++i )
+    {
+      mContactCardLayouter.AddContact( ContactData::TABLE[ i ].name, ContactData::TABLE[ i ].address, ContactData::TABLE[ i ].imagePath );
+    }
+  }
+
+  /**
+   * @brief Called when any key event is received
+   *
+   * Will use this to quit the application if Back or the Escape key is received
+   * @param[in] event The key event information
+   */
+  void OnKeyEvent( const KeyEvent& event )
+  {
+    if( event.state == KeyEvent::Down )
+    {
+      if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+      {
+        mApplication.Quit();
+      }
+    }
+  }
+
+  Application& mApplication; ///< Reference to the application class.
+  ContactCardLayouter mContactCardLayouter; ///< The contact card layouter.
+};
+
+int DALI_EXPORT_API main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv, THEME_PATH );
+  ContactCardController contactCardController( application );
+  application.MainLoop();
+  return 0;
+}
diff --git a/examples/contact-cards/contact-data.cpp b/examples/contact-cards/contact-data.cpp
new file mode 100644 (file)
index 0000000..5ff3163
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include "contact-data.h"
+
+namespace ContactData
+{
+
+const Item TABLE[] =
+{
+  { "Shelia Ramos",       "19 Wormley Ct\nWinters Way\nWaltham Abbey\nEN9 3HW", DEMO_IMAGE_DIR "gallery-small-19.jpg" },
+  { "Walter Jensen",      "32 Upper Fant Rd\nMaidstone\nME16 8DN",              DEMO_IMAGE_DIR "gallery-small-2.jpg" },
+  { "Randal Parks",       "8 Rymill St\nLondon\nE16 2JF",                       DEMO_IMAGE_DIR "gallery-small-3.jpg" },
+  { "Tasha Cooper",       "2 Kyles View\nColintraive\nPA22 3AS",                DEMO_IMAGE_DIR "gallery-small-4.jpg" },
+  { "Domingo Lynch",      "Red Lion Farm\nWatlington\nOX49 5LG",                DEMO_IMAGE_DIR "gallery-small-5.jpg" },
+  { "Dan Haynes",         "239 Whitefield Dr\nLiverpool\nL32 0RD",              DEMO_IMAGE_DIR "gallery-small-6.jpg" },
+  { "Leslie Wong",        "1 Tullyvar Rd\nAughnacloy\nBT69 6BQ",                DEMO_IMAGE_DIR "gallery-small-7.jpg" },
+  { "Mable Hodges",       "5 Mortimer Rd\nGrazeley\nReading\nRG7 1LA",          DEMO_IMAGE_DIR "gallery-small-8.jpg" },
+  { "Kristi Riley",       "10 Jura Dr\nOld Kilpatrick\nGlasgow\nG60 5EH",       DEMO_IMAGE_DIR "gallery-small-17.jpg" },
+  { "Terry Clark",        "142 Raeberry St\nGlasgow\nG20 6EA",                  DEMO_IMAGE_DIR "gallery-small-18.jpg" },
+  { "Horace Bailey",      "11 Assembly St\nNormanton\nWF6 2DB",                 DEMO_IMAGE_DIR "gallery-small-11.jpg" },
+  { "Suzanne Delgado",    "6 Grange Rd\nDownpatrick\nBT30 7DB",                 DEMO_IMAGE_DIR "gallery-small-12.jpg" },
+  { "Jamie Bennett",      "117 Potter St\nNorthwood\nHA6 1QF",                  DEMO_IMAGE_DIR "gallery-small-13.jpg" },
+  { "Emmett Yates",       "18 Renfrew Way\nBletchley\nMilton Keynes\nMK3 7NY",  DEMO_IMAGE_DIR "gallery-small-14.jpg" },
+  { "Glen Vaughn",        "5 Hasman Terrace\nCove Bay\nAberdeen\nAB12 3GD",     DEMO_IMAGE_DIR "gallery-small-15.jpg" },
+};
+const size_t TABLE_SIZE = sizeof( TABLE ) / sizeof( TABLE[ 0 ] );
+
+} // namespace ContactData
diff --git a/examples/contact-cards/contact-data.h b/examples/contact-cards/contact-data.h
new file mode 100644 (file)
index 0000000..0036774
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef CONTACT_DATA_H
+#define CONTACT_DATA_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstddef>
+
+namespace ContactData
+{
+
+/**
+ * @brief The information for an individual contact.
+ */
+struct Item
+{
+  const char * const name; ///< The name of the contact.
+  const char * const address; ///< The address of the contact.
+  const char * const imagePath; ///< The path to the image that represents the contact.
+};
+
+extern const Item TABLE[]; ///< The table that has the information for all the contacts.
+extern const size_t TABLE_SIZE; ///< The size of TABLE. Can use this to iterate through TABLE.
+
+} // namespace ContactData
+
+#endif // CONTACT_DATA_H
index 66883d0e4d8a24e149bb709a142c81ad12f9167e..fc7c20467023389e10c2c7440b519bfcae3dca4e 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "ক্লিক্"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "ঝুৰ্"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "অঁপইতা "
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "ঘনক পৰিৱৰ্তনীয় প্ৰভাৱ"
 
index 7901ce02ebd8cc4f8b42b0d019b41c19643ba867..7d3e41caafa7e81260465e2d0f6470a2c2921879 100755 (executable)
@@ -11,7 +11,10 @@ msgid "DALI_DEMO_STR_TITLE_BUTTONS"
 msgstr "Tasten"
 
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
-msgstr "Farbverlauf "
+msgstr "Farbverlauf"
+
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "Kontakt"
 
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "Würfel Übergangseffekt"
index b248e0fb3cb031cb781c4c6a198b142d19eabdc0..e90637b4f9039dcdf75a0709c3e07733761ff4f7 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "Buttons"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "Colour Gradient"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "Contact Cards"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "Cube Effect"
 
index 8b7d4e9877a87f4c99cd2516e5df698486332cca..1d6c984d616c56d5be00e85edf3c8bb7f56ef4a0 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "Buttons"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "Color Gradient"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "Contact Cards"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "Cube Effect"
 
index cfef651c1e6bcee946d04a448cdf3cd97003f437..1454c5033272ea1e2d4831c8b4ca7576de8470b0 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "Botones"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "Gradiente de color"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "Contactos"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "Transición cubos"
 
index 1bf812c5d831647cbb9a21419ebb4fa45700facb..dcbfb24158dadf5cf1d6ffdd4f8596d2223b918e 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "Painikkeet"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "Liukuväri"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "Yhteystietokortit"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "Kuutioefekti"
 
index a09b572cb9aa588dc2342e56c73a74664b1b1a99..69775e47271848f9b1ab984cd5cb2f097930cd03 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "버튼"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "색상 그라디언트"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "접촉"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "입방체 전환"
 
index d439c774ce7de10e22045f22bfafb2f0acead770..10fd9e36d780c835adeb4393f1aa007763d8a708 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "ബട്ടണുകൾ"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "വർണ്ണ ഗ്രേഡിയന്റ്"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "ബന്ധങ്ങൾ"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "സമചതുരക്കട്ട സംക്രമണ ഇഫക്ട്"
 
index 1548a1ec16f90aeb0ef976020039d662dc4cf12e..49d552f1e8905b4ffc0432392917830e91b0a7f0 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "بٹنوں"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "رنگ میلان"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "لوگ"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "کیوب منتقلی"
 
index af3ef775bd7e8d0d50ee81ba46cbde1b2258da4b..b26841115ebf08d63d0a5c03542ce2b8c40b09d7 100755 (executable)
@@ -13,6 +13,9 @@ msgstr "按钮"
 msgid "DALI_DEMO_STR_TITLE_COLOR_GRADIENT"
 msgstr "颜色梯度"
 
+msgid "DALI_DEMO_STR_TITLE_CONTACT_CARDS"
+msgstr "往来"
+
 msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION"
 msgstr "方块切换效果"
 
index 59620ccc9dc50b20b2166f2dd031c8885840e3e4..d967080033da66292ba928dcda59aae0472a6bef 100644 (file)
@@ -1,4 +1,5 @@
 demo-theme.json
+contact-cards-example-theme.json
 style-example-theme-three.json
 style-example-theme-two.json
 style-example-theme-one.json
diff --git a/resources/style/contact-cards-example-theme.json.in b/resources/style/contact-cards-example-theme.json.in
new file mode 100644 (file)
index 0000000..3a1448f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+{
+  "styles":
+  {
+    "ContactNameTextLabel":
+    {
+      "textColor": [ 0, 0, 0, 1 ],
+      "horizontalAlignment": "CENTER",
+      "pointSize": 14
+    },
+
+    "ContactDetailTextLabel":
+    {
+      "textColor": [ 0, 0, 0, 1 ],
+      "multiLine": true,
+      "pointSize": 20
+    }
+  }
+}
diff --git a/resources/style/mobile/contact-cards-example-theme.json.in b/resources/style/mobile/contact-cards-example-theme.json.in
new file mode 100644 (file)
index 0000000..03ece78
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+{
+  "styles":
+  {
+    "ContactNameTextLabel":
+    {
+      "textColor": [ 0, 0, 0, 1 ],
+      "horizontalAlignment": "CENTER",
+      "pointSize": 7
+    },
+
+    "ContactDetailTextLabel":
+    {
+      "textColor": [ 0, 0, 0, 1 ],
+      "multiLine": true,
+      "pointSize": 13
+    }
+  }
+}
index 60d80494c7d1682010fbb5d4bdaa6d60697f6c41..750fd8476d872e13ee3e37634fb2fde9addeeb60 100644 (file)
@@ -37,6 +37,7 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_BUBBLES                     dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_BUBBLES")
 #define DALI_DEMO_STR_TITLE_BUTTONS                     dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_BUTTONS")
 #define DALI_DEMO_STR_TITLE_COLOR_GRADIENT              dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_COLOR_GRADIENT")
+#define DALI_DEMO_STR_TITLE_CONTACT_CARDS               dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CONTACT_CARDS")
 #define DALI_DEMO_STR_TITLE_CUBE_TRANSITION             dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CUBE_TRANSITION")
 #define DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION         dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION")
 #define DALI_DEMO_STR_TITLE_EFFECTS_VIEW                dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_EFFECTS_VIEW")
@@ -87,6 +88,7 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_BUBBLES                     "Bubbles"
 #define DALI_DEMO_STR_TITLE_BUTTONS                     "Buttons"
 #define DALI_DEMO_STR_TITLE_COLOR_GRADIENT              "Color Gradient"
+#define DALI_DEMO_STR_TITLE_CONTACT_CARDS               "Contact Cards"
 #define DALI_DEMO_STR_TITLE_CUBE_TRANSITION             "Cube Effect"
 #define DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION         "Dissolve Effect"
 #define DALI_DEMO_STR_TITLE_EFFECTS_VIEW                "Effects View"