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.
21 #include "shared/view.h"
23 #include <dali-toolkit/dali-toolkit.h>
24 #include <dali-toolkit/devel-api/controls/magnifier/magnifier.h>
29 const char* BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-magnifier.jpg" );
30 const char* TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
31 const char* APPLICATION_TITLE( "Magnifier Example" );
32 const Vector3 MAGNIFIER_SIZE(0.25f, 0.25f, 0.0f); ///< Magnifier sides should be 25% of the width of the window
33 const float ANIMATION_DURATION(60.0f); ///< Run animation for a minute before repeating.
34 const float MAGNIFIER_DISPLAY_DURATION(0.125f); ///< Duration in seconds for show/hide manual magnifier animation
36 const float MAGNIFICATION_FACTOR(2.0f); ///< Amount to magnify by.
37 const float MAGNIFIER_INDENT(10.0f); ///< Indentation around edge of window to define where magnifiers may move.
38 const float FINGER_RADIUS_INCHES(0.25f); ///< Average finger radius in inches from the center of index finger to edge.
41 * MagnifierPathConstraint
42 * This constraint governs the position of the
43 * animating magnifier in a swirly pattern around
46 struct MagnifierPathConstraint
49 * Constraint constructor
50 * @param[in] windowSize The window size so that the constraint can create a path
51 * within window bounds.
53 MagnifierPathConstraint(const Vector3& windowSize,
54 Vector3 offset = Vector3::ZERO)
55 : mWindowSize(windowSize),
60 void operator()( Vector3& current, const PropertyInputContainer& inputs )
62 float time = inputs[1]->GetFloat();
63 const Vector3& size = inputs[0]->GetVector3();
67 Vector3 range( mWindowSize - size - Vector3::ONE * MAGNIFIER_INDENT * 2.0f );
68 current.x += 0.5f * sinf(time * 0.471f) * range.width;
69 current.y += 0.5f * sinf(time * 0.8739f) * range.height;
72 Vector3 mWindowSize; ///< Keep track of the window size for determining path within window bounds
73 Vector3 mOffset; ///< Amount to offset magnifier path
77 * Confine Actor to boundaries of reference actor (e.g. Parent)
78 * Actor bounds (top-left position + size) are confined to reference Actor's
81 struct ConfinementConstraint
84 * Confinement constraint constructor.
85 * @param[in] offsetOrigin (optional) Whether to offset the parent origin or not.
86 * @param[in] topLeftMargin (optional) Top-Left margins (defaults to 0.0f, 0.0f)
87 * @param[in] bottomRightMargin (optional) Bottom-Right margins (defaults to 0.0f, 0.0f)
88 * @param[in] flipHorizontal (optional) whether to flip Actor to the other side X if near edge, and by
89 * how much (defaults to 0.0f i.e. no flip)
90 * @param[in] flipVertical (optional) whether to flip Actor to the other side Y if near edge, and by
91 * how much (defaults to 0.0f i.e. no flip)
93 ConfinementConstraint(Vector3 offsetOrigin = Vector3::ZERO, Vector2 topLeftMargin = Vector2::ZERO, Vector2 bottomRightMargin = Vector2::ZERO, bool flipHorizontal = false, bool flipVertical = false)
94 : mOffsetOrigin(offsetOrigin),
95 mMinIndent(topLeftMargin),
96 mMaxIndent(bottomRightMargin),
97 mFlipHorizontal(flipHorizontal),
98 mFlipVertical(flipVertical)
102 void operator()( Vector3& current, const PropertyInputContainer& inputs )
104 const Vector3& size = inputs[0]->GetVector3();
105 const Vector3 origin = inputs[1]->GetVector3();
106 const Vector3& anchor = inputs[2]->GetVector3();
107 const Vector3& referenceSize = inputs[3]->GetVector3();
109 Vector3 offset(mOffsetOrigin * referenceSize);
111 // Get actual position of Actor relative to parent's Top-Left.
112 Vector3 position(current + offset + origin * referenceSize);
116 // if top-left corner is outside of Top-Left bounds, then push back in screen.
117 Vector3 corner(position - size * anchor - mMinIndent);
119 if(mFlipHorizontal && corner.x < 0.0f)
122 current.x += size.width;
125 if(mFlipVertical && corner.y < 0.0f)
128 current.y += size.height;
131 current.x -= std::min(corner.x, 0.0f);
132 current.y -= std::min(corner.y, 0.0f);
134 // if bottom-right corner is outside of Bottom-Right bounds, then push back in screen.
135 corner += size - referenceSize + mMinIndent + mMaxIndent;
137 if(mFlipHorizontal && corner.x > 0.0f)
140 current.x -= size.width;
143 if(mFlipVertical && corner.y > 0.0f)
146 current.y -= size.height;
149 current.x -= std::max(corner.x, 0.0f);
150 current.y -= std::max(corner.y, 0.0f);
153 Vector3 mOffsetOrigin; ///< Manual Parent Offset Origin.
154 Vector3 mMinIndent; ///< Top-Left Margin
155 Vector3 mMaxIndent; ///< Bottom-Right Margin.
156 bool mFlipHorizontal; ///< Whether to flip actor's position if exceeds horizontal screen bounds
157 bool mFlipVertical; ///< Whether to flip actor's position if exceeds vertical screen bounds
162 // This example shows how to use the Magnifier component.
164 class ExampleController : public ConnectionTracker
169 * The example controller constructor.
170 * @param[in] application The application instance
172 ExampleController( Application& application )
173 : mApplication( application ),
175 mAnimationTime(0.0f),
176 mAnimationTimeProperty( Property::INVALID_INDEX ),
177 mMagnifierShown(false)
179 // Connect to the Application's Init signal
180 mApplication.InitSignal().Connect( this, &ExampleController::Create );
184 * The example controller destructor
188 // Nothing to do here;
192 * Invoked upon creation of application
193 * @param[in] application The application instance
195 void Create( Application& application )
197 Window window = application.GetWindow();
198 window.KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
199 mWindowSize = window.GetSize();
201 // The Init signal is received once (only) during the Application lifetime
203 // Creates a default view with a default tool bar.
204 // The view is added to the window.
205 Toolkit::ToolBar toolBar;
206 mContent = DemoHelper::CreateView( application,
213 mContent.SetProperty( Actor::Property::LEAVE_REQUIRED,true);
214 mContent.TouchSignal().Connect( this, &ExampleController::OnTouched );
216 // Create magnifier (controlled by human touch)
217 Layer overlay = Layer::New();
218 overlay.SetProperty( Actor::Property::SENSITIVE,false);
219 overlay.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
220 overlay.SetProperty( Actor::Property::SIZE, mWindowSize);
223 mMagnifier = Toolkit::Magnifier::New();
224 mMagnifier.SetSourceActor( mView );
225 mMagnifier.SetProperty( Actor::Property::SIZE, MAGNIFIER_SIZE * mWindowSize.width ); // Size of magnifier is in relation to window width
226 mMagnifier.SetProperty( Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR, MAGNIFICATION_FACTOR );
227 mMagnifier.SetProperty( Actor::Property::SCALE,Vector3::ZERO);
228 overlay.Add( mMagnifier );
230 // Apply constraint to animate the position of the magnifier.
231 Constraint constraint = Constraint::New<Vector3>( mMagnifier, Actor::Property::POSITION, ConfinementConstraint(Vector3( 0.5f, 0.5f, 0.0f ), Vector2::ONE * MAGNIFIER_INDENT, Vector2::ONE * MAGNIFIER_INDENT) );
232 constraint.AddSource( LocalSource(Actor::Property::SIZE) );
233 constraint.AddSource( LocalSource(Actor::Property::PARENT_ORIGIN) );
234 constraint.AddSource( LocalSource(Actor::Property::ANCHOR_POINT) );
235 constraint.AddSource( ParentSource(Actor::Property::SIZE) );
236 constraint.SetRemoveAction(Constraint::Discard);
239 // Create bouncing magnifier automatically bounces around screen.
240 mBouncingMagnifier = Toolkit::Magnifier::New();
241 mBouncingMagnifier.SetSourceActor( mView );
242 mBouncingMagnifier.SetProperty( Actor::Property::SIZE, MAGNIFIER_SIZE * mWindowSize.width ); // Size of magnifier is in relation to window width
243 mBouncingMagnifier.SetProperty( Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR, MAGNIFICATION_FACTOR );
244 overlay.Add( mBouncingMagnifier );
246 mAnimationTimeProperty = mBouncingMagnifier.RegisterProperty("animationTime", 0.0f);
249 // Apply constraint to animate the position of the magnifier.
250 constraint = Constraint::New<Vector3>( mBouncingMagnifier, Actor::Property::POSITION, MagnifierPathConstraint(mWindowSize, mWindowSize * 0.5f) );
251 constraint.AddSource( LocalSource(Actor::Property::SIZE) );
252 constraint.AddSource( LocalSource(mAnimationTimeProperty) );
255 // Apply constraint to animate the source of the magnifier.
256 constraint = Constraint::New<Vector3>( mBouncingMagnifier, Toolkit::Magnifier::Property::SOURCE_POSITION, MagnifierPathConstraint(mWindowSize) );
257 constraint.AddSource( LocalSource(Actor::Property::SIZE) );
258 constraint.AddSource( LocalSource(mAnimationTimeProperty) );
263 * Invoked whenever the animation finishes (every 60 seconds)
264 * @param[in] animation The animation
266 void OnAnimationFinished( Animation& animation )
268 animation.FinishedSignal().Disconnect(this, &ExampleController::OnAnimationFinished);
274 * Resumes animation for another ANIMATION_DURATION seconds.
276 void ContinueAnimation()
278 Animation animation = Animation::New(ANIMATION_DURATION);
279 mAnimationTime += ANIMATION_DURATION;
280 animation.AnimateTo( Property(mBouncingMagnifier, mAnimationTimeProperty), mAnimationTime );
282 animation.FinishedSignal().Connect(this, &ExampleController::OnAnimationFinished);
286 * Invoked whenever the quit button is clicked
287 * @param[in] button the quit button
289 bool OnQuitButtonClicked( Toolkit::Button button )
291 // quit the application
297 * Invoked whenever the content (screen) is touched
298 * @param[in] actor The actor that received the touch
299 * @param[in] event The touch-event information
301 bool OnTouched( Actor actor, const TouchData& event )
303 if(event.GetPointCount() > 0)
305 switch( event.GetState( 0 ) )
307 case PointState::DOWN:
308 case PointState::MOTION:
314 case PointState::LEAVE:
315 case PointState::INTERRUPTED:
320 case PointState::STATIONARY:
326 Vector3 touchPoint( event.GetScreenPosition( 0 ) );
328 SetMagnifierPosition(touchPoint - mWindowSize * 0.5f);
335 * Shows the magnifier
341 Animation animation = Animation::New(MAGNIFIER_DISPLAY_DURATION);
342 animation.AnimateTo(Property(mMagnifier, Actor::Property::SCALE), Vector3::ONE, AlphaFunction::EASE_IN);
344 mMagnifierShown = true;
349 * Hides the magnifier
355 Animation animation = Animation::New(MAGNIFIER_DISPLAY_DURATION);
356 animation.AnimateTo(Property(mMagnifier, Actor::Property::SCALE), Vector3::ZERO, AlphaFunction::EASE_OUT);
358 mMagnifierShown = false;
363 * Manually sets the magnifier position
364 * @param[in] position The magnifier's position relative to center of window
366 void SetMagnifierPosition(const Vector3 position)
368 mMagnifier.SetProperty( Toolkit::Magnifier::Property::SOURCE_POSITION, position );
370 // position magnifier glass such that bottom edge is touching/near top of finger.
371 Vector3 glassPosition(position);
372 glassPosition.y -= mWindowSize.width * MAGNIFIER_SIZE.height * 0.5f + mApplication.GetWindow().GetDpi().GetHeight() * FINGER_RADIUS_INCHES;
374 mMagnifier.SetProperty( Actor::Property::POSITION, glassPosition );
377 void OnKeyEvent(const KeyEvent& event)
379 if(event.state == KeyEvent::Down)
381 if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
390 Application& mApplication; ///< Application instance
391 Toolkit::Control mView; ///< The view
392 Layer mContent; ///< The content layer
393 Toolkit::Magnifier mMagnifier; ///< The manually controlled magnifier
394 Toolkit::Magnifier mBouncingMagnifier; ///< The animating magnifier (swirly animation)
395 Vector3 mWindowSize; ///< The size of the window
396 float mAnimationTime; ///< Keep track of start animation time.
397 Property::Index mAnimationTimeProperty; ///< Animation time property (responsible for swirly animation)
398 bool mMagnifierShown; ///< Flag indicating whether the magnifier is being shown or not.
402 int DALI_EXPORT_API main( int argc, char **argv )
404 Application application = Application::New( &argc, &argv, DEMO_THEME_PATH );
405 ExampleController test( application );
406 application.MainLoop();