From: Adeel Kazmi Date: Tue, 25 Oct 2016 20:36:06 +0000 (+0100) Subject: Added an example which shows a layout containing animating contact cards X-Git-Tag: dali_1.2.14~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e0d5c698d57eaee2da5688c5219a6d0775a96c6f;p=platform%2Fcore%2Fuifw%2Fdali-demo.git Added an example which shows a layout containing animating contact cards Change-Id: Ic59f2e05275694ed1730628b9a1ac4950a759e3f --- diff --git a/.gitignore b/.gitignore index 156dc317..c714b70d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/build/tizen/CMakeLists.txt b/build/tizen/CMakeLists.txt index 575f2b6a..1f119ad9 100644 --- a/build/tizen/CMakeLists.txt +++ b/build/tizen/CMakeLists.txt @@ -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 ) diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index fb4f507b..14e92da6 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -169,4 +169,7 @@ + + + diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp index b39b0702..8c8142aa 100644 --- a/demo/dali-demo.cpp +++ b/demo/dali-demo.cpp @@ -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 index 00000000..ef2f6451 --- /dev/null +++ b/examples/contact-cards/README.md @@ -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 index 00000000..c27a5f62 --- /dev/null +++ b/examples/contact-cards/clipped-image.cpp @@ -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 + +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 index 00000000..edfd86a5 --- /dev/null +++ b/examples/contact-cards/clipped-image.h @@ -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 +#include + +/** + * @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 index 00000000..68e3f20f --- /dev/null +++ b/examples/contact-cards/contact-card-layout-info.h @@ -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 + +/** + * @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 index 00000000..c638f836 --- /dev/null +++ b/examples/contact-cards/contact-card-layouter.cpp @@ -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 + +// 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 index 00000000..ed4d17bb --- /dev/null +++ b/examples/contact-cards/contact-card-layouter.h @@ -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 +#include +#include +#include + +// 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 index 00000000..eb89a6cb --- /dev/null +++ b/examples/contact-cards/contact-card.cpp @@ -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 + +// 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 index 00000000..043bfdeb --- /dev/null +++ b/examples/contact-cards/contact-card.h @@ -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 +#include +#include +#include +#include + +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 index 00000000..d9c4d579 --- /dev/null +++ b/examples/contact-cards/contact-cards-example.cpp @@ -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 +#include +#include +#include +#include + +// 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 index 00000000..5ff31631 --- /dev/null +++ b/examples/contact-cards/contact-data.cpp @@ -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 index 00000000..00367741 --- /dev/null +++ b/examples/contact-cards/contact-data.h @@ -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 + +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 diff --git a/resources/po/as.po b/resources/po/as.po index 66883d0e..fc7c2046 100755 --- a/resources/po/as.po +++ b/resources/po/as.po @@ -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 "ঘনক পৰিৱৰ্তনীয় প্ৰভাৱ" diff --git a/resources/po/de.po b/resources/po/de.po index 7901ce02..7d3e41ca 100755 --- a/resources/po/de.po +++ b/resources/po/de.po @@ -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" diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po index b248e0fb..e90637b4 100755 --- a/resources/po/en_GB.po +++ b/resources/po/en_GB.po @@ -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" diff --git a/resources/po/en_US.po b/resources/po/en_US.po index 8b7d4e98..1d6c984d 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -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" diff --git a/resources/po/es.po b/resources/po/es.po index cfef651c..1454c503 100755 --- a/resources/po/es.po +++ b/resources/po/es.po @@ -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" diff --git a/resources/po/fi.po b/resources/po/fi.po index 1bf812c5..dcbfb241 100755 --- a/resources/po/fi.po +++ b/resources/po/fi.po @@ -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" diff --git a/resources/po/ko.po b/resources/po/ko.po index a09b572c..69775e47 100755 --- a/resources/po/ko.po +++ b/resources/po/ko.po @@ -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 "입방체 전환" diff --git a/resources/po/ml.po b/resources/po/ml.po index d439c774..10fd9e36 100755 --- a/resources/po/ml.po +++ b/resources/po/ml.po @@ -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 "സമചതുരക്കട്ട സംക്രമണ ഇഫക്ട്" diff --git a/resources/po/ur.po b/resources/po/ur.po index 1548a1ec..49d552f1 100755 --- a/resources/po/ur.po +++ b/resources/po/ur.po @@ -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 "کیوب منتقلی" diff --git a/resources/po/zn_CH.po b/resources/po/zn_CH.po index af3ef775..b2684111 100755 --- a/resources/po/zn_CH.po +++ b/resources/po/zn_CH.po @@ -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 "方块切换效果" diff --git a/resources/style/.gitignore b/resources/style/.gitignore index 59620ccc..d9670800 100644 --- a/resources/style/.gitignore +++ b/resources/style/.gitignore @@ -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 index 00000000..3a1448f2 --- /dev/null +++ b/resources/style/contact-cards-example-theme.json.in @@ -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 index 00000000..03ece785 --- /dev/null +++ b/resources/style/mobile/contact-cards-example-theme.json.in @@ -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 + } + } +} diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index 60d80494..750fd847 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -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"