From c973151b54264a643b5cf15fcc904b351b116c31 Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Wed, 17 Oct 2018 18:37:40 +0100 Subject: [PATCH] (ContactCards) Use a mask image when not animating & add Back/Esc key handling to fold contact-cards - 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 | 165 ++++++++++++++++------- examples/contact-cards/contact-card.h | 25 +++- examples/contact-cards/contact-cards-example.cpp | 14 +- examples/contact-cards/masked-image.cpp | 47 +++++++ examples/contact-cards/masked-image.h | 44 ++++++ resources/images/contact-cards-mask.png | Bin 0 -> 3295 bytes 6 files changed, 237 insertions(+), 58 deletions(-) create mode 100644 examples/contact-cards/masked-image.cpp create mode 100644 examples/contact-cards/masked-image.h create mode 100644 resources/images/contact-cards-mask.png diff --git a/examples/contact-cards/contact-card.cpp b/examples/contact-cards/contact-card.cpp index 61fd38e..60d3d0a 100644 --- a/examples/contact-cards/contact-card.cpp +++ b/examples/contact-cards/contact-card.cpp @@ -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. @@ -20,10 +20,12 @@ // EXTERNAL INCLUDES #include +#include // 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(); + } + } } } diff --git a/examples/contact-cards/contact-card.h b/examples/contact-cards/contact-card.h index 043bfde..c922e58 100644 --- a/examples/contact-cards/contact-card.h +++ b/examples/contact-cards/contact-card.h @@ -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 #include +#include #include #include #include @@ -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. diff --git a/examples/contact-cards/contact-cards-example.cpp b/examples/contact-cards/contact-cards-example.cpp index d9c4d57..a0967a1 100644 --- a/examples/contact-cards/contact-cards-example.cpp +++ b/examples/contact-cards/contact-cards-example.cpp @@ -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. @@ -21,12 +21,14 @@ #include #include #include +#include // 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 index 0000000..abf7001 --- /dev/null +++ b/examples/contact-cards/masked-image.cpp @@ -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 + +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 index 0000000..9fefc84 --- /dev/null +++ b/examples/contact-cards/masked-image.h @@ -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 +#include + +/** + * @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 index 0000000000000000000000000000000000000000..d2866c6ff9426e8cf8592b4a735664ff443f512e GIT binary patch literal 3295 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