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>
23 using namespace Dali::Toolkit;
28 const Property::Value BACKGROUND{
29 {Toolkit::Visual::Property::TYPE, Visual::GRADIENT},
30 {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}},
31 {GradientVisual::Property::START_POSITION, Vector2(0.0f, -0.5f)},
32 {GradientVisual::Property::END_POSITION, Vector2(0.0f, 0.5f)}};
34 const Property::Value CONTROL_BACKGROUND{
35 {Toolkit::Visual::Property::TYPE, Visual::GRADIENT},
36 {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}},
37 {GradientVisual::Property::CENTER, Vector2::ZERO},
38 {GradientVisual::Property::RADIUS, 0.5f}};
40 const float HELP_ANIMATION_DURATION(25.0f);
41 const float HELP_ANIMATION_SEGMENT_TIME(5.0f);
42 const float HELP_ANIMATION_TRANSITION_DURATION(0.75f);
43 const Vector2 HELP_TEXT_POSITION_MULTIPLIER(0.25f, 0.13f);
45 const float SHAKY_ANIMATION_DURATION(0.1f);
46 const float SHAKY_ANIMATION_SEGMENT_TIME(0.05f);
47 const float SHAKY_ANIMATION_ANGLE(1.0f);
49 const float TOUCH_MODE_ANIMATION_DURATION(0.1f);
50 const Vector4 TOUCH_MODE_COLOR(1.0f, 0.7f, 0.7f, 1.0f);
52 const float PAN_MODE_CHANGE_ANIMATION_DURATION(0.25f);
53 const Vector3 PAN_MODE_START_ANIMATION_SCALE(1.2f, 1.2f, 1.0f);
54 const Vector3 PAN_MODE_END_ANIMATION_SCALE(0.8f, 0.8f, 1.0f);
56 const float TAP_ANIMATION_DURATION(0.5f);
57 const Vector4 TAP_ANIMATION_COLOR(0.8f, 0.5, 0.2f, 0.6f);
59 const Vector3 MINIMUM_SCALE(Vector3::ONE);
60 const Vector3 MAXIMUM_SCALE(Vector3::ONE * 2.0f);
61 const float SCALE_BACK_ANIMATION_DURATION(0.25f);
62 const float ROTATE_BACK_ANIMATION_DURATION(0.25f);
65 * @brief Shows the given string between the given start and end times.
67 * Appropriately animates the string into and out of the scene.
69 * @param[in] string The label to display, this is an rvalue reference & will be moved
70 * @param[in] parent The parent to add the label to
71 * @param[in] animation The animation to add the animators created in this function
72 * @param[in] startTime When to start the animators
73 * @param[in] endTime When to end the animators
75 void AddHelpInfo(const std::string&& string, const Vector2& windowSize, Actor parent, Animation animation, float startTime, float endTime)
77 Actor text = TextLabel::New(std::move(string));
78 Vector3 position(windowSize * HELP_TEXT_POSITION_MULTIPLIER);
80 text.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
81 text.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
82 text.SetProperty(Actor::Property::POSITION, position);
83 text.SetProperty(Actor::Property::OPACITY, 0.0f);
84 text.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, Text::HorizontalAlignment::CENTER);
85 text.SetProperty(TextLabel::Property::MULTI_LINE, true);
89 TimePeriod timePeriod(startTime, HELP_ANIMATION_TRANSITION_DURATION);
90 animation.AnimateTo(Property(text, Actor::Property::COLOR_ALPHA), 1.0f, timePeriod);
91 animation.AnimateBy(Property(text, Actor::Property::POSITION_X), -position.x, timePeriod);
94 timePeriod.delaySeconds = endTime;
95 animation.AnimateTo(Property(text, Actor::Property::COLOR_ALPHA), 0.0f, timePeriod);
96 animation.AnimateBy(Property(text, Actor::Property::POSITION_X), -position.x, timePeriod);
99 } // unnamed namespace
102 * @brief This example shows how to use the different gesture detectors available.
104 * - Tapping on the control shows a small rotation animation.
105 * - A Long press on the control puts it into Pan Mode.
106 * - When in Pan mode, the control can be panned (moved).
107 * - When the pan ends, we exit the Pan mode via an animation.
108 * - Pinching the control changes the scale of the control.
110 class GestureExample : public ConnectionTracker
114 * @brief Constructor.
116 * @param[in] application Reference to the application
118 GestureExample(Application& application)
119 : mApplication(application)
121 // Connect to the Application's Init signal
122 application.InitSignal().Connect(this, &GestureExample::Create);
127 * @brief Creates the scene as described in this class' description.
129 * @param[in] application Reference to the application class
131 void Create(Application& application)
133 // Get a handle to the window & connect to the key event signal
134 auto window = application.GetWindow();
135 Vector2 windowSize = window.GetSize();
136 window.KeyEventSignal().Connect(this, &GestureExample::OnKeyEvent);
138 // Create a background with a linear gradient which matches parent size & is placed in the center.
139 Actor background = Control::New();
140 background.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
141 background.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
142 background.SetProperty(Control::Property::BACKGROUND, BACKGROUND);
143 window.Add(background);
145 // Create a control with a circular gradient that we'll use for the gestures and be a quarter of the size of the window.
146 Actor touchControl = Control::New();
147 touchControl.SetProperty(Actor::Property::SIZE, windowSize * 0.25f);
148 touchControl.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
149 touchControl.SetProperty(Control::Property::BACKGROUND, CONTROL_BACKGROUND);
150 background.Add(touchControl);
152 // Connect to the touch signal
153 touchControl.TouchedSignal().Connect(this, &GestureExample::OnTouch);
154 touchControl.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
156 // Create a long press gesture detector, attach the actor & connect
157 mLongPressDetector = LongPressGestureDetector::New();
158 mLongPressDetector.Attach(touchControl);
159 mLongPressDetector.DetectedSignal().Connect(this, &GestureExample::OnLongPress);
161 // Create a pan gesture detector & connect, don't attach the actor as we'll attach it when we detect a long-press
162 mPanDetector = PanGestureDetector::New();
163 mPanDetector.DetectedSignal().Connect(this, &GestureExample::OnPan);
165 // Create a tap gesture detector, attach the actor & connect
166 mTapDetector = TapGestureDetector::New();
167 mTapDetector.Attach(touchControl);
168 mTapDetector.DetectedSignal().Connect(this, &GestureExample::OnTap);
170 // Create a pinch gesture detector, attach the actor & connect
171 mPinchDetector = PinchGestureDetector::New();
172 mPinchDetector.Attach(touchControl);
173 mPinchDetector.DetectedSignal().Connect(this, &GestureExample::OnPinch);
175 // Create a rotation gesture detector, attach the actor & connect
176 mRotationDetector = RotationGestureDetector::New();
177 mRotationDetector.Attach(touchControl);
178 mRotationDetector.DetectedSignal().Connect(this, &GestureExample::OnRotation);
180 // Create an animation which shakes the actor when in Pan mode
181 mShakeAnimation = Animation::New(SHAKY_ANIMATION_DURATION);
182 mShakeAnimation.AnimateBy(Property(touchControl, Actor::Property::ORIENTATION),
183 Quaternion(Degree(SHAKY_ANIMATION_ANGLE), Vector3::ZAXIS),
184 AlphaFunction::BOUNCE,
185 TimePeriod(0.0f, SHAKY_ANIMATION_SEGMENT_TIME));
186 mShakeAnimation.AnimateBy(Property(touchControl, Actor::Property::ORIENTATION),
187 Quaternion(Degree(-SHAKY_ANIMATION_ANGLE), Vector3::ZAXIS),
188 AlphaFunction::BOUNCE,
189 TimePeriod(SHAKY_ANIMATION_SEGMENT_TIME, SHAKY_ANIMATION_SEGMENT_TIME));
191 // Animate help information
192 // Here we just animate some text on the screen to show tips on how to use this example
193 // The help animation loops
194 Animation helpAnimation = Animation::New(HELP_ANIMATION_DURATION);
196 float startTime(0.0f);
197 float endTime(startTime + HELP_ANIMATION_SEGMENT_TIME);
199 AddHelpInfo("Tap image for animation", windowSize, background, helpAnimation, startTime, endTime);
200 AddHelpInfo("Press & Hold image to drag", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME);
201 AddHelpInfo("Pinch image to resize", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME);
202 AddHelpInfo("Move fingers in a circular motion on image to rotate", windowSize, background, helpAnimation, startTime += HELP_ANIMATION_SEGMENT_TIME, endTime += HELP_ANIMATION_SEGMENT_TIME);
203 helpAnimation.SetLooping(true);
204 helpAnimation.Play();
208 * @brief Called when our actor is touched.
210 * @param[in] actor The touched actor
211 * @param[in] touch The touch event
213 bool OnTouch(Actor actor, const TouchEvent& touch)
215 switch(touch.GetState(0))
217 case PointState::DOWN:
219 // When we get a touch point, change the color of the actor.
221 Animation anim = Animation::New(TOUCH_MODE_ANIMATION_DURATION);
222 anim.AnimateTo(Property(actor, Actor::Property::COLOR), TOUCH_MODE_COLOR);
227 case PointState::LEAVE:
229 case PointState::INTERRUPTED:
233 // If we're not panning, change the color back to normal.
235 Animation anim = Animation::New(TOUCH_MODE_ANIMATION_DURATION);
236 anim.AnimateTo(Property(actor, Actor::Property::COLOR), Vector4::ONE);
239 // Stop the shake animation from looping.
240 mShakeAnimation.SetLooping(false);
254 * @brief Called when a long-press gesture is detected on our control.
256 * @param[in] actor The actor that's been long-pressed
257 * @param[in] longPress The long-press gesture information
259 void OnLongPress(Actor actor, const LongPressGesture& longPress)
261 if(longPress.GetState() == GestureState::STARTED)
263 // When we first receive a long press, attach the actor to the pan detector.
264 mPanDetector.Attach(actor);
266 // Do a small animation to indicate to the user that we are in pan mode.
267 Animation anim = Animation::New(PAN_MODE_CHANGE_ANIMATION_DURATION);
268 anim.AnimateTo(Property(actor, Actor::Property::SCALE), actor.GetCurrentProperty<Vector3>(Actor::Property::SCALE) * PAN_MODE_START_ANIMATION_SCALE, AlphaFunction::BOUNCE);
271 // Start the shake animation so the user knows when they are in pan mode.
272 mShakeAnimation.SetLooping(true);
273 mShakeAnimation.Play();
278 * @brief Called when a pan gesture is detected on our control.
280 * @param[in] actor The actor that's been panned
281 * @param[in] pan The pan gesture information
283 void OnPan(Actor actor, const PanGesture& pan)
285 // Just move the actor by the displacement.
287 // As the displacement is in local actor coords, we will have to multiply the displacement by the
288 // actor's scale so that it moves the correct amount in the parent's coordinate system.
289 Vector3 scaledDisplacement(pan.GetDisplacement());
290 scaledDisplacement *= actor.GetCurrentProperty<Vector3>(Actor::Property::SCALE);
292 Vector3 currentPosition;
293 actor.GetProperty(Actor::Property::POSITION).Get(currentPosition);
295 Vector3 newPosition = currentPosition + scaledDisplacement;
296 actor.SetProperty(Actor::Property::POSITION, newPosition);
298 switch(pan.GetState())
300 case GestureState::STARTED:
306 case GestureState::FINISHED:
307 case GestureState::CANCELLED:
309 // If we cancel or finish the pan, do an animation to indicate this and stop the shake animation.
311 Animation anim = Animation::New(PAN_MODE_CHANGE_ANIMATION_DURATION);
312 anim.AnimateTo(Property(actor, Actor::Property::COLOR), Vector4::ONE);
313 anim.AnimateTo(Property(actor, Actor::Property::SCALE), actor.GetCurrentProperty<Vector3>(Actor::Property::SCALE) * PAN_MODE_END_ANIMATION_SCALE, AlphaFunction::BOUNCE);
315 // Move actor back to center if we're out of bounds
316 Vector2 halfWindowSize = Vector2(mApplication.GetWindow().GetSize()) * 0.5f;
317 if((abs(newPosition.x) > halfWindowSize.width) ||
318 (abs(newPosition.y) > halfWindowSize.height))
320 anim.AnimateTo(Property(actor, Actor::Property::POSITION), Vector3::ZERO, AlphaFunction::EASE_IN);
324 // Set end of pan configuration and disconnect the actor from the pan detector
325 mShakeAnimation.SetLooping(false);
327 mPanDetector.Detach(actor);
339 * @brief Called when a tap gesture is detected on our control.
341 * @param[in] actor The actor that's been tapped
342 * @param[in] tap The tap gesture information
344 void OnTap(Actor actor, const TapGesture& tap)
346 // Do a short animation to show a tap has happened.
348 Animation anim = Animation::New(TAP_ANIMATION_DURATION);
349 anim.AnimateBy(Property(actor, Actor::Property::ORIENTATION), Quaternion(ANGLE_360, Vector3::ZAXIS));
350 anim.AnimateTo(Property(actor, Actor::Property::SCALE), Vector3::ONE, AlphaFunction::LINEAR);
351 anim.AnimateTo(Property(actor, Actor::Property::COLOR), TAP_ANIMATION_COLOR, AlphaFunction::BOUNCE);
352 anim.AnimateTo(Property(actor, Actor::Property::POSITION), Vector3::ZERO, AlphaFunction::EASE_OUT_SQUARE);
357 * @brief Called when a pinch gesture is detected on our control.
359 * @param[in] actor The actor that's been pinched
360 * @param[in] pinch The pinch gesture information
362 void OnPinch(Actor actor, const PinchGesture& pinch)
364 switch(pinch.GetState())
366 case GestureState::STARTED:
368 // Starting scale is required so that we know what to multiply the pinch.scale by.
369 mStartingScale = actor.GetCurrentProperty<Vector3>(Actor::Property::SCALE);
373 case GestureState::FINISHED:
374 case GestureState::CANCELLED:
376 Vector3 scale(actor.GetCurrentProperty<Vector3>(Actor::Property::SCALE));
378 // Ensure the actor sizes itself to be within the limits defined.
379 if(scale.x < MINIMUM_SCALE.x)
381 scale = MINIMUM_SCALE;
383 else if(scale.x > MAXIMUM_SCALE.x)
385 scale = MAXIMUM_SCALE;
388 // Do an animation to come back to go back to the limits.
389 Animation anim = Animation::New(SCALE_BACK_ANIMATION_DURATION);
390 anim.AnimateTo(Property(actor, Actor::Property::SCALE), scale, AlphaFunction::LINEAR);
401 actor.SetProperty(Actor::Property::SCALE, mStartingScale * pinch.GetScale());
405 * @brief Called when a rotation gesture is detected on our control.
407 * @param[in] actor The actor that's been pinched
408 * @param[in] rotation The rotation gesture information
410 void OnRotation(Actor actor, const RotationGesture& rotation)
412 switch(rotation.GetState())
414 case GestureState::STARTED:
416 // Starting orientation is required so that we know what to multiply the rotation.rotation by.
417 mStartingOrientation = actor.GetCurrentProperty<Quaternion>(Actor::Property::ORIENTATION);
421 case GestureState::FINISHED:
422 case GestureState::CANCELLED:
424 // Do an animation to come back to go back to the original orientation.
425 Animation anim = Animation::New(ROTATE_BACK_ANIMATION_DURATION);
426 anim.AnimateTo(Property(actor, Actor::Property::ORIENTATION), Quaternion::IDENTITY, AlphaFunction::LINEAR);
437 actor.SetProperty(Actor::Property::ORIENTATION, Quaternion(mStartingOrientation * Quaternion(rotation.GetRotation(), Vector3::ZAXIS)));
441 * @brief Called when any key event is received.
443 * Will use this to quit the application if Back or the Escape key is received.
444 * @param[in] event The key event information
446 void OnKeyEvent(const KeyEvent& event)
448 if(event.GetState() == KeyEvent::DOWN)
450 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
458 Application& mApplication;
460 PanGestureDetector mPanDetector;
461 LongPressGestureDetector mLongPressDetector;
462 TapGestureDetector mTapDetector;
463 PinchGestureDetector mPinchDetector;
464 RotationGestureDetector mRotationDetector;
466 Vector3 mStartingScale; ///< Set to the scale of the control when pinch starts.
467 Quaternion mStartingOrientation; ///< Set to the orientation of the control when the rotation starts.
468 Animation mShakeAnimation; ///< "Shake" animation to show when we are in panning mode.
469 bool mPanStarted = false; ///< Set to true to state that panning has started.
472 int DALI_EXPORT_API main(int argc, char** argv)
474 Application application = Application::New(&argc, &argv);
475 GestureExample controller(application);
476 application.MainLoop();