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