Fix for TextLabel demo styling
[platform/core/uifw/dali-demo.git] / examples / magnifier / magnifier-example.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // EXTERNAL INCLUDES
19
20 // INTERNAL INCLUDES
21 #include "shared/view.h"
22
23 #include <dali-toolkit/dali-toolkit.h>
24
25 using namespace Dali;
26
27 namespace
28 {
29 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-magnifier.jpg" );
30 const char* TOOLBAR_IMAGE( DALI_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 stage
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
35
36 const float MAGNIFICATION_FACTOR(2.0f);                 ///< Amount to magnify by.
37 const float MAGNIFIER_INDENT(10.0f);                    ///< Indentation around edge of stage 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.
39
40 /**
41  * MagnifierPathConstraint
42  * This constraint governs the position of the
43  * animating magnifier in a swirly pattern around
44  * the stage.
45  */
46 struct MagnifierPathConstraint
47 {
48   /**
49    * Constraint constructor
50    * @param[in] stageSize The stage size so that the constraint can create a path
51    * within stage bounds.
52    */
53   MagnifierPathConstraint(const Vector3& stageSize,
54                           Vector3 offset = Vector3::ZERO)
55   : mStageSize(stageSize),
56     mOffset(offset)
57   {
58   }
59
60   Vector3 operator()(const Vector3&    current,
61                      const PropertyInput& sizeProperty,
62                      const PropertyInput& animationTimeProperty)
63   {
64     float time = animationTimeProperty.GetFloat();
65     const Vector3& size = sizeProperty.GetVector3();
66
67     Vector3 range(mStageSize - size - Vector3::ONE * MAGNIFIER_INDENT * 2.0f);
68     Vector3 position(mOffset);
69
70     position.x += 0.5f * sinf(time * 0.471f) * range.width;
71     position.y += 0.5f * sinf(time * 0.8739f) * range.height;
72
73     return position;
74   }
75
76   Vector3 mStageSize;     ///< Keep track of the stage size for determining path within stage bounds
77   Vector3 mOffset;        ///< Amount to offset magnifier path
78 };
79
80 /**
81  * Confine Actor to boundaries of reference actor (e.g. Parent)
82  * Actor bounds (top-left position + size) are confined to reference Actor's
83  * bounds.
84  */
85 struct ConfinementConstraint
86 {
87   /**
88    * Confinement constraint constructor.
89    * @param[in] offsetOrigin (optional) Whether to offset the parent origin or not.
90    * @param[in] topLeftMargin (optional) Top-Left margins (defaults to 0.0f, 0.0f)
91    * @param[in] bottomRightMargin (optional) Bottom-Right margins (defaults to 0.0f, 0.0f)
92    * @param[in] flipHorizontal (optional) whether to flip Actor to the other side X if near edge, and by
93    * how much (defaults to 0.0f i.e. no flip)
94    * @param[in] flipVertical (optional) whether to flip Actor to the other side Y if near edge, and by
95    * how much (defaults to 0.0f i.e. no flip)
96    */
97   ConfinementConstraint(Vector3 offsetOrigin = Vector3::ZERO, Vector2 topLeftMargin = Vector2::ZERO, Vector2 bottomRightMargin = Vector2::ZERO, bool flipHorizontal = false, bool flipVertical = false)
98   : mOffsetOrigin(offsetOrigin),
99     mMinIndent(topLeftMargin),
100     mMaxIndent(bottomRightMargin),
101     mFlipHorizontal(flipHorizontal),
102     mFlipVertical(flipVertical)
103   {
104   }
105
106   Vector3 operator()(const Vector3&    constPosition,
107                      const PropertyInput& sizeProperty,
108                      const PropertyInput& parentOriginProperty,
109                      const PropertyInput& anchorPointProperty,
110                      const PropertyInput& referenceSizeProperty)
111   {
112     const Vector3& size = sizeProperty.GetVector3();
113     const Vector3 origin = parentOriginProperty.GetVector3();
114     const Vector3& anchor = anchorPointProperty.GetVector3();
115     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
116
117     Vector3 offset(mOffsetOrigin * referenceSize);
118
119     Vector3 newPosition( constPosition + offset );
120
121     // Get actual position of Actor relative to parent's Top-Left.
122     Vector3 position(constPosition + offset + origin * referenceSize);
123
124     // if top-left corner is outside of Top-Left bounds, then push back in screen.
125     Vector3 corner(position - size * anchor - mMinIndent);
126
127     if(mFlipHorizontal && corner.x < 0.0f)
128     {
129       corner.x = 0.0f;
130       newPosition.x += size.width;
131     }
132
133     if(mFlipVertical && corner.y < 0.0f)
134     {
135       corner.y = 0.0f;
136       newPosition.y += size.height;
137     }
138
139     newPosition.x -= std::min(corner.x, 0.0f);
140     newPosition.y -= std::min(corner.y, 0.0f);
141
142     // if bottom-right corner is outside of Bottom-Right bounds, then push back in screen.
143     corner += size - referenceSize + mMinIndent + mMaxIndent;
144
145     if(mFlipHorizontal && corner.x > 0.0f)
146     {
147       corner.x = 0.0f;
148       newPosition.x -= size.width;
149     }
150
151     if(mFlipVertical && corner.y > 0.0f)
152     {
153       corner.y = 0.0f;
154       newPosition.y -= size.height;
155     }
156
157     newPosition.x -= std::max(corner.x, 0.0f);
158     newPosition.y -= std::max(corner.y, 0.0f);
159
160     return newPosition;
161   }
162
163   Vector3 mOffsetOrigin;                                ///< Manual Parent Offset Origin.
164   Vector3 mMinIndent;                                   ///< Top-Left Margin
165   Vector3 mMaxIndent;                                   ///< Bottom-Right Margin.
166   bool mFlipHorizontal;                                 ///< Whether to flip actor's position if exceeds horizontal screen bounds
167   bool mFlipVertical;                                   ///< Whether to flip actor's position if exceeds vertical screen bounds
168 };
169
170 }
171
172 // This example shows how to use the Magnifier component.
173 //
174 class ExampleController : public ConnectionTracker
175 {
176 public:
177
178   /**
179    * The example controller constructor.
180    * @param[in] application The application instance
181    */
182   ExampleController( Application& application )
183   : mApplication( application ),
184     mView(),
185     mAnimationTime(0.0f),
186     mMagnifierShown(false)
187   {
188     // Connect to the Application's Init signal
189     mApplication.InitSignal().Connect( this, &ExampleController::Create );
190   }
191
192   /**
193    * The example controller destructor
194    */
195   ~ExampleController()
196   {
197     // Nothing to do here;
198   }
199
200   /**
201    * Invoked upon creation of application
202    * @param[in] application The application instance
203    */
204   void Create( Application& application )
205   {
206     DemoHelper::RequestThemeChange();
207
208     Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
209
210     mStageSize = Stage::GetCurrent().GetSize();
211
212     // The Init signal is received once (only) during the Application lifetime
213
214     // Hide the indicator bar
215     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
216
217     // Creates a default view with a default tool bar.
218     // The view is added to the stage.
219     Toolkit::ToolBar toolBar;
220     mContent = DemoHelper::CreateView( application,
221                                        mView,
222                                        toolBar,
223                                        BACKGROUND_IMAGE,
224                                        TOOLBAR_IMAGE,
225                                        APPLICATION_TITLE );
226
227     mContent.SetLeaveRequired(true);
228     mContent.TouchedSignal().Connect( this, &ExampleController::OnTouched );
229
230     // Create magnifier (controlled by human touch)
231     Layer overlay = Layer::New();
232     overlay.SetRelayoutEnabled( false );
233     overlay.SetSensitive(false);
234     overlay.SetParentOrigin( ParentOrigin::CENTER );
235     overlay.SetSize(mStageSize);
236     Stage::GetCurrent().Add(overlay);
237
238     mMagnifier = Toolkit::Magnifier::New();
239     mMagnifier.SetRelayoutEnabled( false );
240     mMagnifier.SetSourceActor( mView.GetBackgroundLayer() );
241     mMagnifier.SetSize( MAGNIFIER_SIZE * mStageSize.width );  // Size of magnifier is in relation to stage width
242     mMagnifier.SetMagnificationFactor( MAGNIFICATION_FACTOR );
243     mMagnifier.SetScale(Vector3::ZERO);
244     overlay.Add( mMagnifier );
245
246     // Apply constraint to animate the position of the magnifier.
247     Constraint constraint = Constraint::New<Vector3>(Actor::Property::POSITION,
248                                                      LocalSource(Actor::Property::SIZE),
249                                                      LocalSource(Actor::Property::PARENT_ORIGIN),
250                                                      LocalSource(Actor::Property::ANCHOR_POINT),
251                                                      ParentSource(Actor::Property::SIZE),
252                                                      ConfinementConstraint(ParentOrigin::CENTER, Vector2::ONE * MAGNIFIER_INDENT, Vector2::ONE * MAGNIFIER_INDENT));
253     constraint.SetRemoveAction(Constraint::Discard);
254     mMagnifier.ApplyConstraint( constraint );
255
256     // Create bouncing magnifier automatically bounces around screen.
257     mBouncingMagnifier = Toolkit::Magnifier::New();
258     mBouncingMagnifier.SetRelayoutEnabled( false );
259     mBouncingMagnifier.SetSourceActor( mView.GetBackgroundLayer() );
260     mBouncingMagnifier.SetSize( MAGNIFIER_SIZE * mStageSize.width ); // Size of magnifier is in relation to stage width
261     mBouncingMagnifier.SetMagnificationFactor( MAGNIFICATION_FACTOR );
262     overlay.Add( mBouncingMagnifier );
263
264     mAnimationTimeProperty = mBouncingMagnifier.RegisterProperty("animation-time", 0.0f);
265     ContinueAnimation();
266
267     // Apply constraint to animate the position of the magnifier.
268     constraint = Constraint::New<Vector3>(Actor::Property::POSITION,
269                                           LocalSource(Actor::Property::SIZE),
270                                           LocalSource(mAnimationTimeProperty),
271                                           MagnifierPathConstraint(mStageSize, mStageSize * 0.5f));
272     mBouncingMagnifier.ApplyConstraint( constraint );
273
274     // Apply constraint to animate the source of the magnifier.
275     constraint = Constraint::New<Vector3>(mBouncingMagnifier.GetPropertyIndex( Toolkit::Magnifier::SOURCE_POSITION_PROPERTY_NAME ),
276                                           LocalSource(Actor::Property::SIZE),
277                                           LocalSource(mAnimationTimeProperty),
278                                           MagnifierPathConstraint(mStageSize));
279     mBouncingMagnifier.ApplyConstraint( constraint );
280   }
281
282   /**
283    * Invoked whenever the animation finishes (every 60 seconds)
284    * @param[in] animation The animation
285    */
286   void OnAnimationFinished( Animation& animation )
287   {
288     animation.FinishedSignal().Disconnect(this, &ExampleController::OnAnimationFinished);
289     animation.Clear();
290     ContinueAnimation();
291   }
292
293   /**
294    * Resumes animation for another ANIMATION_DURATION seconds.
295    */
296   void ContinueAnimation()
297   {
298     Animation animation = Animation::New(ANIMATION_DURATION);
299     mAnimationTime += ANIMATION_DURATION;
300     animation.AnimateTo( Property(mBouncingMagnifier, mAnimationTimeProperty), mAnimationTime );
301     animation.Play();
302     animation.FinishedSignal().Connect(this, &ExampleController::OnAnimationFinished);
303   }
304
305   /**
306    * Invoked whenever the quit button is clicked
307    * @param[in] button the quit button
308    */
309   bool OnQuitButtonClicked( Toolkit::Button button )
310   {
311     // quit the application
312     mApplication.Quit();
313     return true;
314   }
315
316   /**
317    * Invoked whenever the content (screen) is touched
318    * @param[in] actor The actor that received the touch
319    * @param[in] event The touch-event information
320    */
321   bool OnTouched( Actor actor, const TouchEvent& event )
322   {
323     if(event.GetPointCount() > 0)
324     {
325       const TouchPoint& point = event.GetPoint(0);
326       switch(point.state)
327       {
328         case TouchPoint::Down:
329         case TouchPoint::Motion:
330         {
331           ShowMagnifier();
332           break;
333         }
334         case TouchPoint::Up:
335         case TouchPoint::Leave:
336         case TouchPoint::Interrupted:
337         {
338           HideMagnifier();
339           break;
340         }
341         default:
342         {
343           break;
344         }
345       } // end switch
346
347       Vector3 touchPoint(point.screen);
348
349       SetMagnifierPosition(touchPoint - mStageSize * 0.5f);
350     }
351
352     return false;
353   }
354
355   /**
356    * Shows the magnifier
357    */
358   void ShowMagnifier()
359   {
360     if(!mMagnifierShown)
361     {
362       Animation animation = Animation::New(MAGNIFIER_DISPLAY_DURATION);
363       animation.AnimateTo(Property(mMagnifier, Actor::Property::SCALE), Vector3::ONE, AlphaFunctions::EaseIn);
364       animation.Play();
365       mMagnifierShown = true;
366     }
367   }
368
369   /**
370    * Hides the magnifier
371    */
372   void HideMagnifier()
373   {
374     if(mMagnifierShown)
375     {
376       Animation animation = Animation::New(MAGNIFIER_DISPLAY_DURATION);
377       animation.AnimateTo(Property(mMagnifier, Actor::Property::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut);
378       animation.Play();
379       mMagnifierShown = false;
380     }
381   }
382
383   /**
384    * Manually sets the magnifier position
385    * @param[in] position The magnifier's position relative to center of stage
386    */
387   void SetMagnifierPosition(const Vector3 position)
388   {
389     mMagnifier.SetSourcePosition( position );
390
391     // position magnifier glass such that bottom edge is touching/near top of finger.
392     Vector3 glassPosition(position);
393     glassPosition.y -= mStageSize.width * MAGNIFIER_SIZE.height * 0.5f + Stage::GetCurrent().GetDpi().height * FINGER_RADIUS_INCHES;
394
395     mMagnifier.SetPosition( glassPosition );
396   }
397
398   void OnKeyEvent(const KeyEvent& event)
399   {
400     if(event.state == KeyEvent::Down)
401     {
402       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
403       {
404         mApplication.Quit();
405       }
406     }
407   }
408
409 private:
410
411   Application&  mApplication;                             ///< Application instance
412   Toolkit::View mView;                                    ///< The view
413   Layer mContent;                                         ///< The content layer
414   Toolkit::Magnifier mMagnifier;                          ///< The manually controlled magnifier
415   Toolkit::Magnifier mBouncingMagnifier;                  ///< The animating magnifier (swirly animation)
416   Vector3 mStageSize;                                     ///< The size of the stage
417   float mAnimationTime;                                   ///< Keep track of start animation time.
418   Property::Index mAnimationTimeProperty;                 ///< Animation time property (responsible for swirly animation)
419   bool mMagnifierShown;                                   ///< Flag indicating whether the magnifier is being shown or not.
420
421 };
422
423 void RunTest( Application& application )
424 {
425   ExampleController test( application );
426
427   application.MainLoop();
428 }
429
430 // Entry point for Linux & Tizen applications
431 //
432 int main( int argc, char **argv )
433 {
434   Application application = Application::New( &argc, &argv );
435
436   RunTest( application );
437
438   return 0;
439 }