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