2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/dali-toolkit.h>
21 #include <dali/devel-api/actors/actor-devel.h>
22 #include <dali/devel-api/events/rotation-gesture.h>
23 #include <dali/devel-api/events/rotation-gesture-detector.h>
26 using namespace Dali::Toolkit;
31 const Property::Value BACKGROUND
33 { Toolkit::Visual::Property::TYPE, Visual::GRADIENT },
34 { GradientVisual::Property::STOP_COLOR, Property::Array{ Vector4( 167.0f, 207.0f, 223.0f, 255.0f ) / 255.0f,
35 Vector4( 0.0f, 64.0f, 137.0f, 255.0f ) / 255.0f } },
36 { GradientVisual::Property::START_POSITION, Vector2( 0.0f, -0.5f ) },
37 { GradientVisual::Property::END_POSITION, Vector2( 0.0f, 0.5f ) }
40 const Property::Value CONTROL_BACKGROUND
42 { Toolkit::Visual::Property::TYPE, Visual::GRADIENT },
43 { GradientVisual::Property::STOP_COLOR, Property::Array{ Vector4( 234.0f, 185.0f, 45.0f, 255.0f ) / 255.0f,
44 Vector4( 199.0f, 152.0f, 16.0f, 255.0f ) / 255.0f } },
45 { GradientVisual::Property::CENTER, Vector2::ZERO },
46 { GradientVisual::Property::RADIUS, 0.5f }
49 const float HELP_ANIMATION_DURATION( 25.0f );
50 const float HELP_ANIMATION_SEGMENT_TIME( 5.0f );
51 const float HELP_ANIMATION_TRANSITION_DURATION( 0.75f );
52 const Vector2 HELP_TEXT_POSITION_MULTIPLIER( 0.25f, 0.13f );
54 const float SHAKY_ANIMATION_DURATION( 0.1f );
55 const float SHAKY_ANIMATION_SEGMENT_TIME( 0.05f );
56 const float SHAKY_ANIMATION_ANGLE( 1.0f );
58 const float TOUCH_MODE_ANIMATION_DURATION( 0.1f );
59 const Vector4 TOUCH_MODE_COLOR( 1.0f, 0.7f, 0.7f, 1.0f );
61 const float PAN_MODE_CHANGE_ANIMATION_DURATION( 0.25f );
62 const Vector3 PAN_MODE_START_ANIMATION_SCALE( 1.2f, 1.2f, 1.0f );
63 const Vector3 PAN_MODE_END_ANIMATION_SCALE( 0.8f, 0.8f, 1.0f );
65 const float TAP_ANIMATION_DURATION( 0.5f );
66 const Vector4 TAP_ANIMATION_COLOR( 0.8f, 0.5, 0.2f, 0.6f );
68 const Vector3 MINIMUM_SCALE( Vector3::ONE );
69 const Vector3 MAXIMUM_SCALE( Vector3::ONE * 2.0f );
70 const float SCALE_BACK_ANIMATION_DURATION( 0.25f );
71 const float ROTATE_BACK_ANIMATION_DURATION( 0.25f );
74 * @brief Shows the given string between the given start and end times.
76 * Appropriately animates the string into and out of the scene.
78 * @param[in] string The label to display, this is an rvalue reference & will be moved
79 * @param[in] parent The parent to add the label to
80 * @param[in] animation The animation to add the animators created in this function
81 * @param[in] startTime When to start the animators
82 * @param[in] endTime When to end the animators
84 void AddHelpInfo( const std::string&& string, const Vector2& windowSize, Actor parent, Animation animation, float startTime, float endTime )
86 Actor text = TextLabel::New( std::move( string ) );
87 Vector3 position( windowSize * HELP_TEXT_POSITION_MULTIPLIER );
89 text.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
90 text.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
91 text.SetProperty( Actor::Property::POSITION, position );
92 text.SetProperty( Actor::Property::OPACITY, 0.0f );
93 text.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, Text::HorizontalAlignment::CENTER );
94 text.SetProperty( TextLabel::Property::MULTI_LINE, true );
98 TimePeriod timePeriod( startTime, HELP_ANIMATION_TRANSITION_DURATION );
99 animation.AnimateTo( Property( text, Actor::Property::COLOR_ALPHA ), 1.0f, timePeriod );
100 animation.AnimateBy( Property( text, Actor::Property::POSITION_X ), -position.x, timePeriod );
103 timePeriod.delaySeconds = endTime;
104 animation.AnimateTo( Property( text, Actor::Property::COLOR_ALPHA ), 0.0f, timePeriod );
105 animation.AnimateBy( Property( text, Actor::Property::POSITION_X ), -position.x, timePeriod );
108 } // unnamed namespace
111 * @brief This example shows how to use the different gesture detectors available.
113 * - Tapping on the control shows a small rotation animation.
114 * - A Long press on the control puts it into Pan Mode.
115 * - When in Pan mode, the control can be panned (moved).
116 * - When the pan ends, we exit the Pan mode via an animation.
117 * - Pinching the control changes the scale of the control.
119 class GestureExample : public ConnectionTracker
124 * @brief Constructor.
126 * @param[in] application Reference to the application
128 GestureExample( Application &application )
129 : mApplication( application )
131 // Connect to the Application's Init signal
132 application.InitSignal().Connect( this, &GestureExample::Create );
138 * @brief Creates the scene as described in this class' description.
140 * @param[in] application Reference to the application class
142 void Create( Application& application )
144 // Get a handle to the window & connect to the key event signal
145 auto window = application.GetWindow();
146 Vector2 windowSize = window.GetSize();
147 window.KeyEventSignal().Connect(this, &GestureExample::OnKeyEvent);
149 // Create a background with a linear gradient which matches parent size & is placed in the center.
150 Actor background = Control::New();
151 background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
152 background.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
153 background.SetProperty( Control::Property::BACKGROUND, BACKGROUND );
154 window.Add( background );
156 // Create a control with a circular gradient that we'll use for the gestures and be a quarter of the size of the window.
157 Actor touchControl = Control::New();
158 touchControl.SetProperty( Actor::Property::SIZE, windowSize * 0.25f );
159 touchControl.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
160 touchControl.SetProperty( Control::Property::BACKGROUND, CONTROL_BACKGROUND );
161 background.Add( touchControl );
163 // Connect to the touch signal
164 touchControl.TouchSignal().Connect( this, &GestureExample::OnTouch );
165 touchControl.SetProperty( Actor::Property::LEAVE_REQUIRED, true );
167 // Create a long press gesture detector, attach the actor & connect
168 mLongPressDetector = LongPressGestureDetector::New();
169 mLongPressDetector.Attach( touchControl );
170 mLongPressDetector.DetectedSignal().Connect( this, &GestureExample::OnLongPress );
172 // Create a pan gesture detector & connect, don't attach the actor as we'll attach it when we detect a long-press
173 mPanDetector = PanGestureDetector::New();
174 mPanDetector.DetectedSignal().Connect( this, &GestureExample::OnPan );
176 // Create a tap gesture detector, attach the actor & connect
177 mTapDetector = TapGestureDetector::New();
178 mTapDetector.Attach( touchControl );
179 mTapDetector.DetectedSignal().Connect( this, &GestureExample::OnTap );
181 // Create a pinch gesture detector, attach the actor & connect
182 mPinchDetector = PinchGestureDetector::New();
183 mPinchDetector.Attach( touchControl );
184 mPinchDetector.DetectedSignal().Connect( this, &GestureExample::OnPinch );
186 // Create a rotation gesture detector, attach the actor & connect
187 mRotationDetector = RotationGestureDetector::New();
188 mRotationDetector.Attach( touchControl );
189 mRotationDetector.DetectedSignal().Connect( this, &GestureExample::OnRotation );
191 // Create an animation which shakes the actor when in Pan mode
192 mShakeAnimation = Animation::New( SHAKY_ANIMATION_DURATION );
193 mShakeAnimation.AnimateBy( Property( touchControl, Actor::Property::ORIENTATION ),
194 Quaternion( Degree( SHAKY_ANIMATION_ANGLE ), Vector3::ZAXIS ),
195 AlphaFunction::BOUNCE,
196 TimePeriod( 0.0f, SHAKY_ANIMATION_SEGMENT_TIME ) );
197 mShakeAnimation.AnimateBy( Property( touchControl, Actor::Property::ORIENTATION ),
198 Quaternion( Degree( -SHAKY_ANIMATION_ANGLE ), Vector3::ZAXIS ),
199 AlphaFunction::BOUNCE,
200 TimePeriod( SHAKY_ANIMATION_SEGMENT_TIME, SHAKY_ANIMATION_SEGMENT_TIME ) );
202 // Animate help information
203 // Here we just animate some text on the screen to show tips on how to use this example
204 // The help animation loops
205 Animation helpAnimation = Animation::New( HELP_ANIMATION_DURATION );
207 float startTime( 0.0f );
208 float endTime( startTime + HELP_ANIMATION_SEGMENT_TIME );
210 AddHelpInfo( "Tap image for animation", windowSize, background, helpAnimation, startTime, endTime );
211 AddHelpInfo( "Press & Hold image to drag", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
212 AddHelpInfo( "Pinch image to resize", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
213 AddHelpInfo( "Move fingers in a circular motion on image to rotate", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME );
214 helpAnimation.SetLooping( true );
215 helpAnimation.Play();
219 * @brief Called when our actor is touched.
221 * @param[in] actor The touched actor
222 * @param[in] touch The touch event
224 bool OnTouch( Actor actor, const TouchEvent& touch )
226 switch( touch.GetState( 0 ) )
228 case PointState::DOWN:
230 // When we get a touch point, change the color of the actor.
232 Animation anim = Animation::New( TOUCH_MODE_ANIMATION_DURATION );
233 anim.AnimateTo( Property( actor, Actor::Property::COLOR ), TOUCH_MODE_COLOR );
238 case PointState::LEAVE:
240 case PointState::INTERRUPTED:
244 // If we're not panning, change the color back to normal.
246 Animation anim = Animation::New( TOUCH_MODE_ANIMATION_DURATION );
247 anim.AnimateTo( Property( actor, Actor::Property::COLOR ), Vector4::ONE );
250 // Stop the shake animation from looping.
251 mShakeAnimation.SetLooping( false );
265 * @brief Called when a long-press gesture is detected on our control.
267 * @param[in] actor The actor that's been long-pressed
268 * @param[in] longPress The long-press gesture information
270 void OnLongPress( Actor actor, const LongPressGesture& longPress )
272 if( longPress.state == Gesture::Started )
274 // When we first receive a long press, attach the actor to the pan detector.
275 mPanDetector.Attach( actor );
277 // Do a small animation to indicate to the user that we are in pan mode.
278 Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
279 anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) * PAN_MODE_START_ANIMATION_SCALE, AlphaFunction::BOUNCE );
282 // Start the shake animation so the user knows when they are in pan mode.
283 mShakeAnimation.SetLooping( true );
284 mShakeAnimation.Play();
289 * @brief Called when a pan gesture is detected on our control.
291 * @param[in] actor The actor that's been panned
292 * @param[in] pan The pan gesture information
294 void OnPan( Actor actor, const PanGesture& pan )
296 // Just move the actor by the displacement.
298 // As the displacement is in local actor coords, we will have to multiply the displacement by the
299 // actor's scale so that it moves the correct amount in the parent's coordinate system.
300 Vector3 scaledDisplacement( pan.displacement );
301 scaledDisplacement *= actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE );
303 Vector3 currentPosition;
304 actor.GetProperty( Actor::Property::POSITION ).Get( currentPosition );
306 Vector3 newPosition = currentPosition + scaledDisplacement;
307 actor.SetProperty( Actor::Property::POSITION, newPosition );
311 case Gesture::Started:
317 case Gesture::Finished:
318 case Gesture::Cancelled:
320 // If we cancel or finish the pan, do an animation to indicate this and stop the shake animation.
322 Animation anim = Animation::New( PAN_MODE_CHANGE_ANIMATION_DURATION );
323 anim.AnimateTo( Property( actor, Actor::Property::COLOR ), Vector4::ONE );
324 anim.AnimateTo( Property( actor, Actor::Property::SCALE ), actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) * PAN_MODE_END_ANIMATION_SCALE, AlphaFunction::BOUNCE );
326 // Move actor back to center if we're out of bounds
327 Vector2 halfWindowSize = Vector2(mApplication.GetWindow().GetSize()) * 0.5f;
328 if( ( abs( newPosition.x ) > halfWindowSize.width ) ||
329 ( abs( newPosition.y ) > halfWindowSize.height ) )
331 anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3::ZERO, AlphaFunction::EASE_IN );
335 // Set end of pan configuration and disconnect the actor from the pan detector
336 mShakeAnimation.SetLooping( false );
338 mPanDetector.Detach( actor );
350 * @brief Called when a tap gesture is detected on our control.
352 * @param[in] actor The actor that's been tapped
353 * @param[in] tap The tap gesture information
355 void OnTap( Actor actor, const TapGesture& tap )
357 // Do a short animation to show a tap has happened.
359 Animation anim = Animation::New( TAP_ANIMATION_DURATION );
360 anim.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( ANGLE_360, Vector3::ZAXIS ) );
361 anim.AnimateTo( Property( actor, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::LINEAR );
362 anim.AnimateTo( Property( actor, Actor::Property::COLOR ), TAP_ANIMATION_COLOR, AlphaFunction::BOUNCE );
363 anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3::ZERO, AlphaFunction::EASE_OUT_SQUARE );
368 * @brief Called when a pinch gesture is detected on our control.
370 * @param[in] actor The actor that's been pinched
371 * @param[in] pinch The pinch gesture information
373 void OnPinch( Actor actor, const PinchGesture& pinch )
375 switch( pinch.state )
377 case Gesture::Started:
379 // Starting scale is required so that we know what to multiply the pinch.scale by.
380 mStartingScale = actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE );
384 case Gesture::Finished:
385 case Gesture::Cancelled:
387 Vector3 scale( actor.GetCurrentProperty< Vector3 >( Actor::Property::SCALE ) );
389 // Ensure the actor sizes itself to be within the limits defined.
390 if ( scale.x < MINIMUM_SCALE.x )
392 scale = MINIMUM_SCALE;
394 else if ( scale.x > MAXIMUM_SCALE.x )
396 scale = MAXIMUM_SCALE;
399 // Do an animation to come back to go back to the limits.
400 Animation anim = Animation::New( SCALE_BACK_ANIMATION_DURATION );
401 anim.AnimateTo( Property( actor, Actor::Property::SCALE ), scale, AlphaFunction::LINEAR );
412 actor.SetProperty( Actor::Property::SCALE, mStartingScale * pinch.scale );
416 * @brief Called when a rotation gesture is detected on our control.
418 * @param[in] actor The actor that's been pinched
419 * @param[in] rotation The rotation gesture information
421 void OnRotation( Actor actor, const RotationGesture& rotation )
423 switch( rotation.state )
425 case Gesture::Started:
427 // Starting orientation is required so that we know what to multiply the rotation.rotation by.
428 mStartingOrientation = actor.GetCurrentProperty< Quaternion >( Actor::Property::ORIENTATION );
432 case Gesture::Finished:
433 case Gesture::Cancelled:
435 // Do an animation to come back to go back to the original orientation.
436 Animation anim = Animation::New( ROTATE_BACK_ANIMATION_DURATION );
437 anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion::IDENTITY, AlphaFunction::LINEAR );
448 actor.SetProperty( Actor::Property::ORIENTATION, Quaternion( mStartingOrientation * Quaternion( rotation.rotation, Vector3::ZAXIS ) ) );
452 * @brief Called when any key event is received.
454 * Will use this to quit the application if Back or the Escape key is received.
455 * @param[in] event The key event information
457 void OnKeyEvent( const KeyEvent& event )
459 if( event.GetState() == KeyEvent::Down )
461 if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
469 Application& mApplication;
471 PanGestureDetector mPanDetector;
472 LongPressGestureDetector mLongPressDetector;
473 TapGestureDetector mTapDetector;
474 PinchGestureDetector mPinchDetector;
475 RotationGestureDetector mRotationDetector;
477 Vector3 mStartingScale; ///< Set to the scale of the control when pinch starts.
478 Quaternion mStartingOrientation; ///< Set to the orientation of the control when the rotation starts.
479 Animation mShakeAnimation; ///< "Shake" animation to show when we are in panning mode.
480 bool mPanStarted = false; ///< Set to true to state that panning has started.
483 int DALI_EXPORT_API main( int argc, char **argv )
485 Application application = Application::New( &argc, &argv );
486 GestureExample controller( application );
487 application.MainLoop();