Replace some Dali::Actor public APIs with new properties
[platform/core/uifw/dali-demo.git] / examples / dissolve-effect / dissolve-effect-example.cpp
1 /*
2  * Copyright (c) 2019 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 #include <math.h>
20
21 // INTERNAL INCLUDES
22 #include "shared/view.h"
23
24 #include <dali/dali.h>
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali-toolkit/dali-toolkit.h>
27 #include <dali-toolkit/devel-api/shader-effects/dissolve-effect.h>
28
29 using namespace Dali;
30
31 using Dali::Toolkit::TextLabel;
32
33 // LOCAL STUFF
34 namespace
35 {
36
37 const char * const TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
38 const char * const APPLICATION_TITLE_HIGHP( "Dissolve Effect(highp)" );
39 const char * const APPLICATION_TITLE_MEDIUMP( "Dissolve Effect(mediump)" );
40 const char * const EFFECT_HIGHP_IMAGE( DEMO_IMAGE_DIR "icon-highp.png" );
41 const char * const EFFECT_HIGHP_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-highp-selected.png" );
42 const char * const EFFECT_MEDIUMP_IMAGE( DEMO_IMAGE_DIR "icon-mediump.png" );
43 const char * const EFFECT_MEDIUMP_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-mediump-selected.png" );
44 const char * const PLAY_ICON( DEMO_IMAGE_DIR "icon-play.png" );
45 const char * const PLAY_ICON_SELECTED( DEMO_IMAGE_DIR "icon-play-selected.png" );
46 const char * const STOP_ICON( DEMO_IMAGE_DIR "icon-stop.png" );
47 const char * const STOP_ICON_SELECTED( DEMO_IMAGE_DIR "icon-stop-selected.png" );
48
49 const char* IMAGES[] =
50 {
51   DEMO_IMAGE_DIR "gallery-large-1.jpg",
52   DEMO_IMAGE_DIR "gallery-large-2.jpg",
53   DEMO_IMAGE_DIR "gallery-large-3.jpg",
54   DEMO_IMAGE_DIR "gallery-large-4.jpg",
55   DEMO_IMAGE_DIR "gallery-large-5.jpg",
56   DEMO_IMAGE_DIR "gallery-large-6.jpg",
57   DEMO_IMAGE_DIR "gallery-large-7.jpg",
58   DEMO_IMAGE_DIR "gallery-large-8.jpg",
59   DEMO_IMAGE_DIR "gallery-large-9.jpg",
60   DEMO_IMAGE_DIR "gallery-large-10.jpg",
61   DEMO_IMAGE_DIR "gallery-large-11.jpg",
62   DEMO_IMAGE_DIR "gallery-large-12.jpg",
63   DEMO_IMAGE_DIR "gallery-large-13.jpg",
64   DEMO_IMAGE_DIR "gallery-large-14.jpg",
65   DEMO_IMAGE_DIR "gallery-large-15.jpg",
66   DEMO_IMAGE_DIR "gallery-large-16.jpg",
67   DEMO_IMAGE_DIR "gallery-large-17.jpg",
68   DEMO_IMAGE_DIR "gallery-large-18.jpg",
69   DEMO_IMAGE_DIR "gallery-large-19.jpg",
70   DEMO_IMAGE_DIR "gallery-large-20.jpg",
71   DEMO_IMAGE_DIR "gallery-large-21.jpg",
72 };
73
74 const int NUM_IMAGES( sizeof(IMAGES) / sizeof(IMAGES[0]) );
75
76 // The duration of the current image staying on screen when slideshow is on
77 const int VIEWINGTIME = 2000; // 2 seconds
78
79 const float TRANSITION_DURATION = 2.5f; //2.5 second
80
81 const float INITIAL_DEPTH = 10.0f;
82
83 /**
84  * @brief Create an image view with an image which would be scaled-down to no more than the stage dimensions.
85  *
86  * Uses image scaling mode SCALE_TO_FILL to resize the image at
87  * load time to cover the entire stage with pixels with no borders,
88  * and filter mode BOX_THEN_LINEAR to sample the image with maximum quality.
89  */
90 Toolkit::ImageView CreateStageFillingImageView( const char * const imagePath )
91 {
92   Size stageSize = Stage::GetCurrent().GetSize();
93   Toolkit::ImageView imageView = Toolkit::ImageView::New();
94   Property::Map map;
95   map[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::IMAGE;
96   map[Toolkit::ImageVisual::Property::URL] = imagePath;
97   map[Toolkit::ImageVisual::Property::DESIRED_WIDTH] = stageSize.x;
98   map[Toolkit::ImageVisual::Property::DESIRED_HEIGHT] = stageSize.y;
99   map[Toolkit::ImageVisual::Property::FITTING_MODE] = FittingMode::SCALE_TO_FILL;
100   map[Toolkit::ImageVisual::Property::SAMPLING_MODE] = SamplingMode::BOX_THEN_LINEAR;
101   map[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = true;
102   imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
103
104   return imageView;
105 }
106
107 } // namespace
108
109 class DissolveEffectApp : public ConnectionTracker
110 {
111 public:
112
113   /**
114    * Constructor
115    * @param application class, stored as reference
116    */
117   DissolveEffectApp( Application& application );
118
119   ~DissolveEffectApp();
120
121 private:
122
123   /**
124    * This method gets called once the main loop of application is up and running
125    */
126   void OnInit( Application& application );
127   /**
128    * PanGesture callback. This method gets called when the pan gesture is detected.
129    * @param[in] actor The actor receiving the pan gesture.
130    * @param[in] gesture The detected pan gesture.
131    */
132   void OnPanGesture( Actor actor, const PanGesture& gesture );
133
134   /**
135    * Set up the animations for transition
136    * @param[in] position The point ( locates within rectange {(0,0),(0,1),(1,0),(1,1)} ) passing through the central line of the dissolve effect
137    * @param[in] displacement The direction of the central line of the dissolve effect
138    */
139   void StartTransition(Vector2 position, Vector2 displacement);
140   /**
141    * Callback function of effect-switch button
142    * Change the precision of the effect shader when the effect button is clicked
143    * @param[in] button The handle of the clicked button
144    */
145   bool OnEffectButtonClicked( Toolkit::Button button );
146   /**
147    * Callback function of slideshow button
148    * Start or stop the automatical image display when the slideshow button is clicked
149    * @param[in] button The handle of the clicked button
150    */
151   bool OnSildeshowButtonClicked( Toolkit::Button button );
152   /**
153    * Callback function of cube transition completed signal
154    * @param[in] effect The cube effect used for the transition
155    * @param[in] imageActor The target imageActor of the completed transition
156    */
157   void OnTransitionCompleted(Animation& source);
158   /**
159    * Callback function of timer tick
160    * The timer is used to count the image display duration after cube transition in slideshow,
161    */
162   bool OnTimerTick();
163
164   /**
165    * Main key event handler
166    */
167   void OnKeyEvent(const KeyEvent& event);
168
169 private:
170   Application&                    mApplication;
171   Toolkit::Control                mView;
172   Toolkit::ToolBar                mToolBar;
173   Layer                           mContent;
174   Toolkit::TextLabel              mTitleActor;
175   Actor                           mParent;
176
177   Toolkit::ImageView              mCurrentImage;
178   Toolkit::ImageView              mNextImage;
179   unsigned int                    mIndex;
180
181   Property::Map                   mDissolveEffect;
182   Property::Map                   mEmptyEffect;
183
184   bool                            mUseHighPrecision;
185   Animation                       mAnimation;
186
187   PanGestureDetector              mPanGestureDetector;
188   bool                            mIsTransiting;
189
190   bool                            mSlideshow;
191   Timer                           mViewTimer;
192   bool                            mTimerReady;
193   unsigned int                    mCentralLineIndex;
194
195   Toolkit::PushButton             mPlayStopButton;
196   Toolkit::PushButton             mEffectChangeButton;
197 };
198
199 DissolveEffectApp::DissolveEffectApp( Application& application )
200 : mApplication( application ),
201   mIndex( 0 ),
202   mUseHighPrecision(true),
203   mIsTransiting( false ),
204   mSlideshow( false ),
205   mTimerReady( false ),
206   mCentralLineIndex( 0 )
207 {
208   mApplication.InitSignal().Connect( this, &DissolveEffectApp::OnInit );
209 }
210
211 DissolveEffectApp::~DissolveEffectApp()
212 {
213   //Nothing to do
214 }
215
216 void DissolveEffectApp::OnInit( Application& application )
217 {
218   Stage::GetCurrent().KeyEventSignal().Connect(this, &DissolveEffectApp::OnKeyEvent);
219
220   // Creates a default view with a default tool bar, the view is added to the stage.
221   mContent = DemoHelper::CreateView( application, mView,mToolBar, "", TOOLBAR_IMAGE, "" );
222
223   // Add an effect-changing button on the right of the tool bar.
224   mEffectChangeButton = Toolkit::PushButton::New();
225   mEffectChangeButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, EFFECT_HIGHP_IMAGE );
226   mEffectChangeButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, EFFECT_HIGHP_IMAGE_SELECTED );
227   mEffectChangeButton.ClickedSignal().Connect( this, &DissolveEffectApp::OnEffectButtonClicked );
228   mToolBar.AddControl( mEffectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
229
230   // Add title to the tool bar.
231   mTitleActor = DemoHelper::CreateToolBarLabel( APPLICATION_TITLE_HIGHP );
232   mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Toolkit::Alignment::HorizontalCenter );
233
234   // Add an slide-show button on the right of the title
235   mPlayStopButton = Toolkit::PushButton::New();
236   mPlayStopButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, PLAY_ICON );
237   mPlayStopButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, PLAY_ICON_SELECTED );
238   mPlayStopButton.ClickedSignal().Connect( this, &DissolveEffectApp::OnSildeshowButtonClicked );
239   mToolBar.AddControl( mPlayStopButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalCenter, DemoHelper::DEFAULT_PLAY_PADDING );
240
241   // use pan gesture to detect the cursor or finger movement
242   mPanGestureDetector = PanGestureDetector::New();
243   mPanGestureDetector.DetectedSignal().Connect( this, &DissolveEffectApp::OnPanGesture );
244
245   mViewTimer = Timer::New( VIEWINGTIME );
246   mViewTimer.TickSignal().Connect( this, &DissolveEffectApp::OnTimerTick );
247   mTimerReady = true;
248
249   // Set size to stage size to avoid seeing a black border on transition
250   mParent = Actor::New();
251   mParent.SetProperty( Actor::Property::SIZE, Stage::GetCurrent().GetSize() );
252   mParent.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
253   mContent.Add( mParent );
254
255   // show the first image
256   mCurrentImage = CreateStageFillingImageView( IMAGES[mIndex] );
257   mCurrentImage.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
258   mCurrentImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
259   mCurrentImage.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
260   mParent.Add( mCurrentImage );
261
262   mPanGestureDetector.Attach( mCurrentImage );
263
264   mDissolveEffect = Dali::Toolkit::CreateDissolveEffect( mUseHighPrecision );
265   Property::Map emptyShaderMap;
266   mEmptyEffect.Insert( "shader", emptyShaderMap );
267 }
268
269 // signal handler, called when the pan gesture is detected
270 void DissolveEffectApp::OnPanGesture( Actor actor, const PanGesture& gesture )
271 {
272   // does not response when the animation has not finished
273   if( mIsTransiting || mSlideshow )
274   {
275     return;
276   }
277
278   if( gesture.state == Gesture::Continuing )
279   {
280     if( gesture.displacement.x < 0)
281     {
282       mIndex = (mIndex + 1)%NUM_IMAGES;
283     }
284     else
285     {
286       mIndex = (mIndex + NUM_IMAGES -1)%NUM_IMAGES;
287     }
288
289     mNextImage = CreateStageFillingImageView( IMAGES[ mIndex ] );
290     mNextImage.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
291     mNextImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
292     mNextImage.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
293     mNextImage.SetProperty( Actor::Property::POSITION_Z, INITIAL_DEPTH);
294     mParent.Add( mNextImage );
295     Vector2 size = Vector2( mCurrentImage.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) );
296     StartTransition( gesture.position / size, gesture.displacement * Vector2(1.0, size.x/size.y));
297   }
298 }
299
300 void DissolveEffectApp::StartTransition(Vector2 position, Vector2 displacement)
301 {
302   mAnimation = Animation::New(TRANSITION_DURATION);
303
304   Dali::Toolkit::DissolveEffectSetCentralLine( mCurrentImage, position, displacement, 0.0f );
305   mCurrentImage.SetProperty( Toolkit::ImageView::Property::IMAGE, mDissolveEffect );
306   mAnimation.AnimateTo( Property( mCurrentImage, "uPercentage" ), 1.0f, AlphaFunction::LINEAR );
307
308   mNextImage.SetProperty( Actor::Property::OPACITY,0.0f);
309   mAnimation.AnimateTo( Property( mNextImage, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::LINEAR );
310
311   if(mUseHighPrecision)
312   {
313     Dali::Toolkit::DissolveEffectSetCentralLine( mNextImage, position, displacement, 1.0f );
314     mNextImage.SetProperty( Toolkit::ImageView::Property::IMAGE, mDissolveEffect );
315     mAnimation.AnimateTo( Property( mNextImage, "uPercentage" ), 0.0f, AlphaFunction::LINEAR );
316   }
317   else
318   {
319     mAnimation.AnimateTo( Property( mNextImage, Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), AlphaFunction::LINEAR );
320   }
321
322   mAnimation.FinishedSignal().Connect( this, &DissolveEffectApp::OnTransitionCompleted );
323   mAnimation.Play();
324   mIsTransiting = true;
325 }
326
327 void DissolveEffectApp::OnKeyEvent(const KeyEvent& event)
328 {
329   if(event.state == KeyEvent::Down)
330   {
331     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
332     {
333       mApplication.Quit();
334     }
335   }
336 }
337
338 bool DissolveEffectApp::OnEffectButtonClicked( Toolkit::Button button )
339 {
340   mUseHighPrecision = !mUseHighPrecision;
341   mDissolveEffect = Dali::Toolkit::CreateDissolveEffect(mUseHighPrecision);
342   if(mUseHighPrecision)
343   {
344     mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_HIGHP) );
345     mEffectChangeButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, EFFECT_HIGHP_IMAGE );
346     mEffectChangeButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, EFFECT_HIGHP_IMAGE_SELECTED );
347   }
348   else
349   {
350     mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_MEDIUMP) );
351     mEffectChangeButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, EFFECT_MEDIUMP_IMAGE );
352     mEffectChangeButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, EFFECT_MEDIUMP_IMAGE_SELECTED );
353   }
354
355   return true;
356 }
357
358 bool DissolveEffectApp::OnSildeshowButtonClicked( Toolkit::Button button )
359 {
360   mSlideshow = !mSlideshow;
361   if( mSlideshow )
362   {
363     mPlayStopButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, STOP_ICON );
364     mPlayStopButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, STOP_ICON_SELECTED );
365     mPanGestureDetector.Detach( mParent );
366     mViewTimer.Start();
367     mTimerReady = false;
368   }
369   else
370   {
371     mPlayStopButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, PLAY_ICON );
372     mPlayStopButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, PLAY_ICON_SELECTED );
373     mTimerReady = true;
374     mPanGestureDetector.Attach( mParent );
375   }
376   return true;
377 }
378
379 void DissolveEffectApp::OnTransitionCompleted( Animation& source )
380 {
381   if(mUseHighPrecision)
382   {
383     mNextImage.SetProperty( Toolkit::ImageView::Property::IMAGE, mEmptyEffect );
384   }
385   mParent.Remove( mCurrentImage );
386   mPanGestureDetector.Detach( mCurrentImage );
387   mCurrentImage = mNextImage;
388   mPanGestureDetector.Attach( mCurrentImage );
389   mIsTransiting = false;
390
391   if( mSlideshow)
392   {
393     mViewTimer.Start();
394     mTimerReady = false;
395   }
396 }
397
398 bool DissolveEffectApp::OnTimerTick()
399 {
400   mTimerReady = true;
401   if(mSlideshow)
402   {
403     mIndex = (mIndex + 1)%NUM_IMAGES;
404     mNextImage = CreateStageFillingImageView( IMAGES[ mIndex ] );
405     mNextImage.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
406     mNextImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
407     mNextImage.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
408     mNextImage.SetProperty( Actor::Property::POSITION_Z, INITIAL_DEPTH);
409     mParent.Add( mNextImage );
410     switch( mCentralLineIndex%4 )
411     {
412       case 0:
413       {
414         StartTransition(Vector2(1.0f,0.5f), Vector2(-1.0f, 0.0f));
415         break;
416       }
417       case 1:
418       {
419         StartTransition(Vector2(0.5f,0.0f), Vector2(0.0f, 1.0f));
420         break;
421       }
422       case 2:
423       {
424         StartTransition(Vector2(0.0f,0.5f), Vector2(1.0f, 0.0f));
425         break;
426       }
427       default:
428       {
429         StartTransition(Vector2(0.5f,1.0f), Vector2(0.0f, -1.0f));
430         break;
431       }
432
433     }
434     mCentralLineIndex++;
435   }
436   return false;   //return false to stop the timer
437 }
438
439 int DALI_EXPORT_API main( int argc, char **argv )
440 {
441   Application application = Application::New( &argc, &argv, DEMO_THEME_PATH );
442   DissolveEffectApp test( application );
443   application.MainLoop();
444
445   return 0;
446 }