/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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 <string>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/events/rotation-gesture.h>
+#include <dali/devel-api/events/rotation-gesture-detector.h>
using namespace Dali;
using namespace Dali::Toolkit;
+using namespace std;
namespace
{
-const Vector4 BACKGROUND_GRADIENT_1 = Vector4( 167.0f, 207.0f, 223.0f, 255.0f ) / 255.0f;
-const Vector4 BACKGROUND_GRADIENT_2 = Vector4( 0.0f, 64.0f, 137.0f, 255.0f ) / 255.0f;
-const Vector2 BACKGROUND_GRADIENT_START_POSITION( 0.0f, -0.5f );
-const Vector2 BACKGROUND_GRADIENT_END_POSITION( 0.0f, 0.5f );
+const Property::Value BACKGROUND
+{
+ { Toolkit::Visual::Property::TYPE, Visual::GRADIENT },
+ { GradientVisual::Property::STOP_COLOR, Property::Array{ Vector4( 167.0f, 207.0f, 223.0f, 255.0f ) / 255.0f,
+ Vector4( 0.0f, 64.0f, 137.0f, 255.0f ) / 255.0f } },
+ { GradientVisual::Property::START_POSITION, Vector2( 0.0f, -0.5f ) },
+ { GradientVisual::Property::END_POSITION, Vector2( 0.0f, 0.5f ) }
+};
-const Vector4 CONTROL_GRADIENT_1 = Vector4( 234.0f, 185.0f, 45.0f, 255.0f ) / 255.0f;
-const Vector4 CONTROL_GRADIENT_2 = Vector4( 199.0f, 152.0f, 16.0f, 255.0f ) / 255.0f;
-const Vector2 CONTROL_GRADIENT_CENTER( Vector2::ZERO );
-const float CONTROL_GRADIENT_RADIUS( 0.5f );
+const Property::Value CONTROL_BACKGROUND
+{
+ { Toolkit::Visual::Property::TYPE, Visual::GRADIENT },
+ { GradientVisual::Property::STOP_COLOR, Property::Array{ Vector4( 234.0f, 185.0f, 45.0f, 255.0f ) / 255.0f,
+ Vector4( 199.0f, 152.0f, 16.0f, 255.0f ) / 255.0f } },
+ { GradientVisual::Property::CENTER, Vector2::ZERO },
+ { GradientVisual::Property::RADIUS, 0.5f }
+};
const float HELP_ANIMATION_DURATION( 25.0f );
const float HELP_ANIMATION_SEGMENT_TIME( 5.0f );
const Vector3 PAN_MODE_START_ANIMATION_SCALE( 1.2f, 1.2f, 1.0f );
const Vector3 PAN_MODE_END_ANIMATION_SCALE( 0.8f, 0.8f, 1.0f );
-const float TAP_ANIMATION_DURATON( 0.5f );
+const float TAP_ANIMATION_DURATION( 0.5f );
const Vector4 TAP_ANIMATION_COLOR( 0.8f, 0.5, 0.2f, 0.6f );
const Vector3 MINIMUM_SCALE( Vector3::ONE );
const Vector3 MAXIMUM_SCALE( Vector3::ONE * 2.0f );
const float SCALE_BACK_ANIMATION_DURATION( 0.25f );
-
-/**
- * @brief Creates a background with a linear gradient which matches parent size & is placed in the center.
- */
-Actor CreateBackground()
-{
- Actor background = Control::New();
- background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
- background.SetParentOrigin( ParentOrigin::CENTER );
- background.SetProperty(
- Control::Property::BACKGROUND,
- Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::GRADIENT )
- .Add( GradientVisual::Property::STOP_COLOR, Property::Array().Add( BACKGROUND_GRADIENT_1 )
- .Add( BACKGROUND_GRADIENT_2 ) )
- .Add( GradientVisual::Property::START_POSITION, BACKGROUND_GRADIENT_START_POSITION )
- .Add( GradientVisual::Property::END_POSITION, BACKGROUND_GRADIENT_END_POSITION ) );
- return background;
-}
-
-/**
- * @brief Create a control with a circular gradient & a specific size & is placed in the center of its parent.
- *
- * @param[in] size The size we want the control to be.
- */
-Actor CreateTouchControl( const Vector2& size )
-{
- Actor touchControl = Control::New();
- touchControl.SetSize( size );
- touchControl.SetParentOrigin( ParentOrigin::CENTER );
- touchControl.SetProperty(
- Control::Property::BACKGROUND,
- Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::GRADIENT )
- .Add( GradientVisual::Property::STOP_COLOR, Property::Array().Add( CONTROL_GRADIENT_1 )
- .Add( CONTROL_GRADIENT_2 ) )
- .Add( GradientVisual::Property::CENTER, CONTROL_GRADIENT_CENTER )
- .Add( GradientVisual::Property::RADIUS, CONTROL_GRADIENT_RADIUS )
- );
- return touchControl;
-}
+const float ROTATE_BACK_ANIMATION_DURATION( 0.25f );
/**
* @brief Shows the given string between the given start and end times.
* @param[in] startTime When to start the animators
* @param[in] endTime When to end the animators
*/
-void AddHelpInfo( const std::string&& string, Actor parent, Animation animation, float startTime, float endTime )
+void AddHelpInfo( const std::string&& string, const Vector2& windowSize, Actor parent, Animation animation, float startTime, float endTime )
{
Actor text = TextLabel::New( std::move( string ) );
- Vector3 position( Stage::GetCurrent().GetSize() * HELP_TEXT_POSITION_MULTIPLIER );
+ Vector3 position( windowSize * HELP_TEXT_POSITION_MULTIPLIER );
- text.SetAnchorPoint( AnchorPoint::TOP_CENTER );
- text.SetParentOrigin( ParentOrigin::TOP_CENTER );
- text.SetPosition( position );
- text.SetOpacity( 0.0f );
+ text.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
+ text.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
+ text.SetProperty( Actor::Property::POSITION, position );
+ text.SetProperty( Actor::Property::OPACITY, 0.0f );
text.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, Text::HorizontalAlignment::CENTER );
+ text.SetProperty( TextLabel::Property::MULTI_LINE, true );
parent.Add( text );
// Animate IN
*/
void Create( Application& application )
{
- // Get a handle to the stage & connect to the key event signal
- Stage stage = Stage::GetCurrent();
- stage.KeyEventSignal().Connect(this, &GestureExample::OnKeyEvent);
-
- // Create a background with a gradient
- Actor background = CreateBackground();
- stage.Add( background );
-
- // Create a control that we'll use for the gestures to be a quarter of the size of the stage
- Actor touchControl = CreateTouchControl( stage.GetSize() * 0.25f );
+ // Get a handle to the window & connect to the key event signal
+ auto window = application.GetWindow();
+ Vector2 windowSize = window.GetSize();
+ window.KeyEventSignal().Connect(this, &GestureExample::OnKeyEvent);
+
+ // Create a background with a linear gradient which matches parent size & is placed in the center.
+ Actor background = Control::New();
+ background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+ background.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ background.SetProperty( Control::Property::BACKGROUND, BACKGROUND );
+ window.Add( background );
+
+ // Create a control with a circular gradient that we'll use for the gestures and be a quarter of the size of the window.
+ Actor touchControl = Control::New();
+ touchControl.SetProperty( Actor::Property::SIZE, windowSize * 0.25f );
+ touchControl.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+ touchControl.SetProperty( Control::Property::BACKGROUND, CONTROL_BACKGROUND );
background.Add( touchControl );
// Connect to the touch signal
touchControl.TouchSignal().Connect( this, &GestureExample::OnTouch );
- touchControl.SetLeaveRequired( true );
+ touchControl.SetProperty( Actor::Property::LEAVE_REQUIRED, true );
// Create a long press gesture detector, attach the actor & connect
mLongPressDetector = LongPressGestureDetector::New();
mLongPressDetector.Attach( touchControl );
mLongPressDetector.DetectedSignal().Connect( this, &GestureExample::OnLongPress );
- // Create a pan gesture detector, attach the actor & connect
+ // Create a pan gesture detector & connect, don't attach the actor as we'll attach it when we detect a long-press
mPanDetector = PanGestureDetector::New();
- mPanDetector.Attach( touchControl );
mPanDetector.DetectedSignal().Connect( this, &GestureExample::OnPan );
// Create a tap gesture detector, attach the actor & connect
mPinchDetector.Attach( touchControl );
mPinchDetector.DetectedSignal().Connect( this, &GestureExample::OnPinch );
+ // Create a rotation gesture detector, attach the actor & connect
+ mRotationDetector = RotationGestureDetector::New();
+ mRotationDetector.Attach( touchControl );
+ mRotationDetector.DetectedSignal().Connect( this, &GestureExample::OnRotation );
+
// Create an animation which shakes the actor when in Pan mode
mShakeAnimation = Animation::New( SHAKY_ANIMATION_DURATION );
mShakeAnimation.AnimateBy( Property( touchControl, Actor::Property::ORIENTATION ),
float startTime( 0.0f );
float endTime( startTime + HELP_ANIMATION_SEGMENT_TIME );
- AddHelpInfo( "Tap image for animation", background, helpAnimation, startTime, endTime );
- AddHelpInfo( "Press & Hold image to drag", background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
- AddHelpInfo( "Pinch image to resize", background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
+ AddHelpInfo( "Tap image for animation", windowSize, background, helpAnimation, startTime, endTime );
+ AddHelpInfo( "Press & Hold image to drag", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
+ AddHelpInfo( "Pinch image to resize", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
+ AddHelpInfo( "Move fingers in a circular motion on image to rotate", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
helpAnimation.SetLooping( true );
helpAnimation.Play();
}
*/
void OnLongPress( Actor actor, const LongPressGesture& longPress )
{
- switch( longPress.state )
+ if( longPress.state == Gesture::Started )
{
- case Gesture::Started:
- {
- // When we first receive a long press, change state to pan mode.
+ // When we first receive a long press, attach the actor to the pan detector.
+ mPanDetector.Attach( actor );
- // Do a small animation to indicate to the user that we are in pan mode.
- Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
- anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentScale() * PAN_MODE_START_ANIMATION_SCALE, AlphaFunction::BOUNCE );
- anim.Play();
- mPanMode = true;
+ // Do a small animation to indicate to the user that we are in pan mode.
+ Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
+ anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) * PAN_MODE_START_ANIMATION_SCALE, AlphaFunction::BOUNCE );
+ anim.Play();
- // Start the shake animation so the user knows when they are in pan mode.
- mShakeAnimation.SetLooping( true );
- mShakeAnimation.Play();
- break;
- }
-
- case Gesture::Finished:
- case Gesture::Cancelled:
- {
- // We get this state when all touches are released after a long press. We end pan mode...
- mPanMode = false;
- break;
- }
-
- default:
- {
- break;
- }
+ // Start the shake animation so the user knows when they are in pan mode.
+ mShakeAnimation.SetLooping( true );
+ mShakeAnimation.Play();
}
}
*/
void OnPan( Actor actor, const PanGesture& pan )
{
- if( mPanMode || mPanStarted )
- {
- // When we are in Pan mode, just move the actor by the displacement.
+ // Just move the actor by the displacement.
- // As the displacement is in local actor coords, we will have to multiply the displacement by the
- // actor's scale so that it moves the correct amount in the parent's coordinate system.
- Vector3 scaledDisplacement( pan.displacement );
- scaledDisplacement *= actor.GetCurrentScale();
+ // As the displacement is in local actor coords, we will have to multiply the displacement by the
+ // actor's scale so that it moves the correct amount in the parent's coordinate system.
+ Vector3 scaledDisplacement( pan.displacement );
+ scaledDisplacement *= actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE );
- Vector3 currentPosition;
- actor.GetProperty( Actor::Property::POSITION ).Get( currentPosition );
+ Vector3 currentPosition;
+ actor.GetProperty( Actor::Property::POSITION ).Get( currentPosition );
- Vector3 newPosition = currentPosition + scaledDisplacement;
- actor.SetPosition( newPosition );
+ Vector3 newPosition = currentPosition + scaledDisplacement;
+ actor.SetProperty( Actor::Property::POSITION, newPosition );
- switch( pan.state )
+ switch( pan.state )
+ {
+ case Gesture::Started:
{
- case Gesture::Started:
- {
- mPanStarted = true;
- break;
- }
-
- case Gesture::Finished:
- case Gesture::Cancelled:
- {
- // If we cancel or finish the pan, do an animation to indicate this and stop the shake animation.
+ mPanStarted = true;
+ break;
+ }
- Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
- anim.AnimateTo( Property( actor, Actor::Property::COLOR ), Vector4::ONE );
- anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentScale() * PAN_MODE_END_ANIMATION_SCALE, AlphaFunction::BOUNCE );
-
- // Move actor back to center if we're out of bounds
- Vector2 halfStageSize = Stage::GetCurrent().GetSize() * 0.5f;
- if( ( std::abs( newPosition.x ) > halfStageSize.width ) ||
- ( std::abs( newPosition.y ) > halfStageSize.height ) )
- {
- anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3::ZERO, AlphaFunction::EASE_IN );
- }
- anim.Play();
+ case Gesture::Finished:
+ case Gesture::Cancelled:
+ {
+ // If we cancel or finish the pan, do an animation to indicate this and stop the shake animation.
- mShakeAnimation.SetLooping( false );
- mPanStarted = false;
- break;
- }
+ Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
+ anim.AnimateTo( Property( actor, Actor::Property::COLOR ), Vector4::ONE );
+ anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) * PAN_MODE_END_ANIMATION_SCALE, AlphaFunction::BOUNCE );
- default:
+ // Move actor back to center if we're out of bounds
+ Vector2 halfWindowSize = Vector2(mApplication.GetWindow().GetSize()) * 0.5f;
+ if( ( abs( newPosition.x ) > halfWindowSize.width ) ||
+ ( abs( newPosition.y ) > halfWindowSize.height ) )
{
- break;
+ anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3::ZERO, AlphaFunction::EASE_IN );
}
+ anim.Play();
+
+ // Set end of pan configuration and disconnect the actor from the pan detector
+ mShakeAnimation.SetLooping( false );
+ mPanStarted = false;
+ mPanDetector.Detach( actor );
+ break;
+ }
+
+ default:
+ {
+ break;
}
}
}
{
// Do a short animation to show a tap has happened.
- Animation anim = Animation::New( TAP_ANIMATION_DURATON );
- anim.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Degree( 360.0f ), Vector3::ZAXIS ) );
+ Animation anim = Animation::New( TAP_ANIMATION_DURATION );
+ anim.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( ANGLE_360, Vector3::ZAXIS ) );
anim.AnimateTo( Property( actor, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::LINEAR );
anim.AnimateTo( Property( actor, Actor::Property::COLOR ), TAP_ANIMATION_COLOR, AlphaFunction::BOUNCE );
+ anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3::ZERO, AlphaFunction::EASE_OUT_SQUARE );
anim.Play();
}
case Gesture::Started:
{
// Starting scale is required so that we know what to multiply the pinch.scale by.
- mStartingScale = actor.GetCurrentScale();
+ mStartingScale = actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE );
break;
}
case Gesture::Finished:
case Gesture::Cancelled:
{
- Vector3 scale( actor.GetCurrentScale() );
+ Vector3 scale( actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) );
// Ensure the actor sizes itself to be within the limits defined.
if ( scale.x < MINIMUM_SCALE.x )
}
}
- actor.SetScale( mStartingScale * pinch.scale );
+ actor.SetProperty( Actor::Property::SCALE, mStartingScale * pinch.scale );
+ }
+
+ /**
+ * @brief Called when a rotation gesture is detected on our control.
+ *
+ * @param[in] actor The actor that's been pinched
+ * @param[in] rotation The rotation gesture information
+ */
+ void OnRotation( Actor actor, const RotationGesture& rotation )
+ {
+ switch( rotation.state )
+ {
+ case Gesture::Started:
+ {
+ // Starting orientation is required so that we know what to multiply the rotation.rotation by.
+ mStartingOrientation = actor.GetCurrentProperty< Quaternion >( Actor::Property::ORIENTATION );
+ break;
+ }
+
+ case Gesture::Finished:
+ case Gesture::Cancelled:
+ {
+ // Do an animation to come back to go back to the original orientation.
+ Animation anim = Animation::New( ROTATE_BACK_ANIMATION_DURATION );
+ anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion::IDENTITY, AlphaFunction::LINEAR );
+ anim.Play();
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+ actor.SetProperty( Actor::Property::ORIENTATION, Quaternion( mStartingOrientation * Quaternion( rotation.rotation, Vector3::ZAXIS ) ) );
}
/**
LongPressGestureDetector mLongPressDetector;
TapGestureDetector mTapDetector;
PinchGestureDetector mPinchDetector;
+ RotationGestureDetector mRotationDetector;
Vector3 mStartingScale; ///< Set to the scale of the control when pinch starts.
+ Quaternion mStartingOrientation; ///< Set to the orientation of the control when the rotation starts.
Animation mShakeAnimation; ///< "Shake" animation to show when we are in panning mode.
- bool mPanMode = false; ///< Set to true when we have long-pressed to put us into panning mode.
bool mPanStarted = false; ///< Set to true to state that panning has started.
};