(ContactCards) Use a mask image when not animating & add Back/Esc key handling to... 11/191511/2
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 17 Oct 2018 17:37:40 +0000 (18:37 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 17 Oct 2018 17:46:50 +0000 (18:46 +0100)
- Applying a mask is better quality
- When a contact card is unfolded and Esc/Back is pressed, the contact card is folded
  - Before we used to Quit the application

Change-Id: I85f245dea9e24b98e312a7870129b2c44711ba2d

examples/contact-cards/contact-card.cpp
examples/contact-cards/contact-card.h
examples/contact-cards/contact-cards-example.cpp
examples/contact-cards/masked-image.cpp [new file with mode: 0644]
examples/contact-cards/masked-image.h [new file with mode: 0644]
resources/images/contact-cards-mask.png [new file with mode: 0644]

index 61fd38e..60d3d0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 
 // INTERNAL INCLUDES
 #include "contact-card-layout-info.h"
 #include "clipped-image.h"
+#include "masked-image.h"
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -93,14 +95,20 @@ ContactCard::ContactCard(
   mContactCard(),
   mHeader(),
   mClippedImage(),
+  mMaskedImage(),
   mNameText(),
   mDetailText(),
+  mAnimation(),
   mSlotDelegate( this ),
   mContactCardLayoutInfo( contactCardLayoutInfo ),
   foldedPosition( position ),
   mClippedImagePropertyIndex( Property::INVALID_INDEX ),
   mFolded( true )
 {
+  // Connect to the stage's key signal to allow Back and Escape to fold a contact card if it is unfolded
+  Stage stage = Stage::GetCurrent();
+  stage.KeyEventSignal().Connect( mSlotDelegate, &ContactCard::OnKeyEvent );
+
   // Create a control which will be used for the background and to clip the contents
   mContactCard = Control::New();
   mContactCard.SetProperty( Control::Property::BACKGROUND,
@@ -111,7 +119,7 @@ ContactCard::ContactCard(
   mContactCard.SetAnchorPoint( AnchorPoint::TOP_LEFT );
   mContactCard.SetPosition( foldedPosition.x, foldedPosition.y );
   mContactCard.SetSize( mContactCardLayoutInfo.foldedSize );
-  Stage::GetCurrent().Add( mContactCard );
+  stage.Add( mContactCard );
 
   // Create the header which will be shown only when the contact is unfolded
   mHeader = Control::New();
@@ -129,8 +137,17 @@ ContactCard::ContactCard(
   mClippedImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
   mClippedImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
   mClippedImage.SetPosition( mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y );
+  mClippedImage.SetVisible( false ); // Hide image as we only want to display it if we are animating or unfolded
   mContactCard.Add( mClippedImage );
 
+  // Create an image with a mask which is to be used when the contact is folded
+  mMaskedImage = MaskedImage::Create( imagePath );
+  mMaskedImage.SetSize( mContactCardLayoutInfo.imageSize );
+  mMaskedImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mMaskedImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mMaskedImage.SetPosition( mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y );
+  mContactCard.Add( mMaskedImage );
+
   // Add the text label for just the name
   mNameText = TextLabel::New( contactName );
   mNameText.SetStyleName( "ContactNameTextLabel" );
@@ -167,112 +184,158 @@ ContactCard::~ContactCard()
   }
 }
 
-void ContactCard::OnTap( Actor actor, const TapGesture& gesture )
+void ContactCard::OnTap( Actor actor, const TapGesture& /* gesture */ )
+{
+  if( actor == mContactCard )
+  {
+    Animate();
+  }
+}
+
+void ContactCard::Animate()
 {
+  KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
+
+  mAnimation = Animation::New( 0.0f ); // Overall duration is unimportant as superseded by TimePeriods set later
+
   if( mFolded )
   {
+    // Set key-input-focus to our contact-card so that we can fold the contact-card if we receive a Back or Esc key
+    keyInputFocusManager.SetFocus( mContactCard );
+
     mContactCard.Add( mHeader );
     mContactCard.Add( mDetailText );
 
+    // Show clipped-image to animate geometry and hide the masked-image
+    mClippedImage.SetVisible( true );
+    mMaskedImage.SetVisible( false );
+
     // 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 );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.unfoldedPosition.x,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.unfoldedPosition.y,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ),  mContactCardLayoutInfo.unfoldedSize.width,  ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_WIDTH );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.imageUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.imageUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_NAME_OPACITY );
+    mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_DETAIL_OPACITY );
+    mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
+    mAnimation.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();
+    Actor parent = mContactCard.GetParent();
     for( size_t i = 0; i < parent.GetChildCount(); ++i )
     {
       Actor sibling = parent.GetChildAt( i );
-      if( sibling != actor )
+      if( sibling != mContactCard )
       {
-        animation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_SIBLING_OPACITY );
+        mAnimation.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();
+    mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
+    mAnimation.Play();
   }
   else
   {
+    // Remove key-input-focus from our contact-card when we are folded
+    keyInputFocusManager.RemoveFocus( mContactCard );
+
     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 );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ),  foldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ),  foldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+    mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ),  mContactCardLayoutInfo.foldedSize.width,  ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_WIDTH );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.imageFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ),  mContactCardLayoutInfo.imageFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_NAME_OPACITY );
+    mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    mAnimation.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 );
+    mAnimation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_DETAIL_OPACITY );
+    mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ),  mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
+    mAnimation.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();
+    Actor parent = mContactCard.GetParent();
     for( size_t i = 0; i < parent.GetChildCount(); ++i )
     {
       Actor sibling = parent.GetChildAt( i );
-      if( sibling != actor )
+      if( sibling != mContactCard )
       {
-        animation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_SIBLING_OPACITY );
+        mAnimation.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();
+    mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
+    mAnimation.Play();
   }
 
   mFolded = !mFolded;
 }
 
-void ContactCard::OnAnimationFinished( Dali::Animation& animation )
+void ContactCard::OnAnimationFinished( Animation& animation )
 {
-  if( mFolded )
+  // Ensure the finishing animation is the latest as we do not want to change state if a previous animation has finished
+  if( mAnimation == animation )
   {
-    mHeader.Unparent();
-    mDetailText.Unparent();
+    if( mFolded )
+    {
+      mHeader.Unparent();
+      mDetailText.Unparent();
+
+      // Hide the clipped-image as we have finished animating the geometry and show the masked-image again
+      mClippedImage.SetVisible( false );
+      mMaskedImage.SetVisible( true );
+    }
+    else
+    {
+      mNameText.Unparent();
+    }
+    mAnimation.Reset();
   }
-  else
+}
+
+void ContactCard::OnKeyEvent( const KeyEvent& event )
+{
+  if( ( ! mFolded ) && // If we're folded then there's no need to do any more checking
+      ( event.state == KeyEvent::Down ) )
   {
-    mNameText.Unparent();
+    if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+    {
+      KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
+      if( keyInputFocusManager.GetCurrentFocusControl() == mContactCard )
+      {
+        // Our contact-card is set to receive focus so call OnTap which should trigger the required animation
+        Animate();
+      }
+    }
   }
 }
index 043bfde..c922e58 100644 (file)
@@ -2,7 +2,7 @@
 #define CONTACT_CARD_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <string>
 #include <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/animation.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>
@@ -67,24 +68,40 @@ private:
 
   /**
    * @brief Called when this contact card is tapped.
-   * @param[in] actor The tapped actor.
-   * @param[in] gesture The tap gesture.
+   * @param[in]  actor    The tapped actor.
+   * @param[in]  gesture  The tap gesture.
    */
   void OnTap( Dali::Actor actor, const Dali::TapGesture& gesture );
 
   /**
+   * @brief Animates the fold/unfold animation as required.
+   */
+  void Animate();
+
+  /**
    * @brief Called when the animation finishes.
-   * @param[in] animation The animation which has just finished.
+   * @param[in]  animation  The animation which has just finished.
    */
   void OnAnimationFinished( Dali::Animation& animation );
 
+  /**
+   * @brief Called when any key event is received
+   *
+   * Will use this to fold a contact card if it is unfolded.
+   * @param[in]  event  The key event information
+   */
+  void OnKeyEvent( const Dali::KeyEvent& event );
+
   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 mMaskedImage; ///< The image with a mask (better quality around the edges than the clipped image when folded).
   Dali::Toolkit::Control mNameText; ///< The text shown when folded.
   Dali::Toolkit::Control mDetailText; ///< The text shown when unfolded.
 
+  Dali::Animation mAnimation; ///< The fold/unfold animation.
+
   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.
index d9c4d57..a0967a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/events/key-event.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 
 // INTERNAL INCLUDES
 #include "contact-card-layouter.h"
 #include "contact-data.h"
 
 using namespace Dali;
+using namespace Dali::Toolkit;
 
 namespace
 {
@@ -51,6 +53,8 @@ const char * const THEME_PATH( DEMO_STYLE_DIR "contact-cards-example-theme.json"
  *               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.
+ * MaskedImage: This namespace provides a helper function which creates an ImageView with a mask that matches the Circle geometry provided by ClippedImage.
+ *              Using a mask yields much better quality than when using an image with a circle geometry, so this is ONLY used when the contact card is folded.
  */
 class ContactCardController : public ConnectionTracker // Inherit from ConnectionTracker so that our signals can be automatically disconnected upon our destruction.
 {
@@ -100,9 +104,13 @@ private:
   {
     if( event.state == KeyEvent::Down )
     {
-      if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+      KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
+      if( ! keyInputFocusManager.GetCurrentFocusControl() ) // Don't quit if a control has focus
       {
-        mApplication.Quit();
+        if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+        {
+          mApplication.Quit();
+        }
       }
     }
   }
diff --git a/examples/contact-cards/masked-image.cpp b/examples/contact-cards/masked-image.cpp
new file mode 100644 (file)
index 0000000..abf7001
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 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 "masked-image.h"
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/dali-toolkit.h>
+
+namespace MaskedImage
+{
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* const IMAGE_MASK ( DEMO_IMAGE_DIR "contact-cards-mask.png" );
+} // unnamed namespace
+
+Dali::Toolkit::Control Create( const std::string& imagePath )
+{
+  Control maskedImage = ImageView::New();
+  maskedImage.SetProperty(
+    Toolkit::ImageView::Property::IMAGE,
+    Property::Map().Add( Visual::Property::TYPE, Toolkit::Visual::Type::IMAGE )
+                   .Add( ImageVisual::Property::URL, imagePath )
+                   .Add( ImageVisual::Property::ALPHA_MASK_URL, IMAGE_MASK )
+  );
+  return maskedImage;
+}
+
+} // namespace ClippedImage
diff --git a/examples/contact-cards/masked-image.h b/examples/contact-cards/masked-image.h
new file mode 100644 (file)
index 0000000..9fefc84
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef MASKED_IMAGE_H
+#define MASKED_IMAGE_H
+
+/*
+ * Copyright (c) 2018 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 which creates an ImageView with a mask that matches the Circle geometry provided by ClippedImage.
+ *
+ * Using a mask yields much better quality than when using an image with a circle geometry.
+ * @see ClippedImage
+ */
+namespace MaskedImage
+{
+
+/**
+ * @brief Creates an image with a circular mask.
+ *
+ * @param[in]  imagePath  The path to the image to show.
+ * @return The ImageView with a mask control.
+ */
+Dali::Toolkit::Control Create( const std::string& imagePath );
+
+} // namespace ClippedImage
+
+#endif // MASKED_IMAGE_H
diff --git a/resources/images/contact-cards-mask.png b/resources/images/contact-cards-mask.png
new file mode 100644 (file)
index 0000000..d2866c6
Binary files /dev/null and b/resources/images/contact-cards-mask.png differ