Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / cube-transition-effect / cube-transition-effect-example.cpp
1 /*
2  * Copyright (c) 2020 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/utility.h"
23 #include "shared/view.h"
24
25 #include <dali-toolkit/dali-toolkit.h>
26 #include <dali-toolkit/devel-api/controls/buttons/toggle-button.h>
27 #include <dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h>
28 #include <dali-toolkit/devel-api/transition-effects/cube-transition-effect.h>
29 #include <dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h>
30 #include <dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h>
31 #include <dali/dali.h>
32
33 using namespace Dali;
34
35 using Dali::Toolkit::TextLabel;
36
37 // LOCAL STUFF
38 namespace
39 {
40 const char* const TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
41 const char* const APPLICATION_TITLE_WAVE("Cube Transition: Wave");
42 const char* const APPLICATION_TITLE_CROSS("Cube Transition: Cross");
43 const char* const APPLICATION_TITLE_FOLD("Cube Transition: Fold");
44 const char* const EFFECT_WAVE_IMAGE(DEMO_IMAGE_DIR "icon-effect-wave.png");
45 const char* const EFFECT_WAVE_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-effect-wave-selected.png");
46 const char* const EFFECT_CROSS_IMAGE(DEMO_IMAGE_DIR "icon-effect-cross.png");
47 const char* const EFFECT_CROSS_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-effect-cross-selected.png");
48 const char* const EFFECT_FOLD_IMAGE(DEMO_IMAGE_DIR "icon-effect-fold.png");
49 const char* const EFFECT_FOLD_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-effect-fold-selected.png");
50 const char* const SLIDE_SHOW_START_ICON(DEMO_IMAGE_DIR "icon-play.png");
51 const char* const SLIDE_SHOW_START_ICON_SELECTED(DEMO_IMAGE_DIR "icon-play-selected.png");
52 const char* const SLIDE_SHOW_STOP_ICON(DEMO_IMAGE_DIR "icon-stop.png");
53 const char* const SLIDE_SHOW_STOP_ICON_SELECTED(DEMO_IMAGE_DIR "icon-stop-selected.png");
54
55 const char* IMAGES[] =
56   {
57     DEMO_IMAGE_DIR "gallery-large-1.jpg",
58     DEMO_IMAGE_DIR "gallery-large-2.jpg",
59     DEMO_IMAGE_DIR "gallery-large-3.jpg",
60     DEMO_IMAGE_DIR "gallery-large-4.jpg",
61     DEMO_IMAGE_DIR "gallery-large-5.jpg",
62     DEMO_IMAGE_DIR "gallery-large-6.jpg",
63     DEMO_IMAGE_DIR "gallery-large-7.jpg",
64     DEMO_IMAGE_DIR "gallery-large-8.jpg",
65     DEMO_IMAGE_DIR "gallery-large-9.jpg",
66     DEMO_IMAGE_DIR "gallery-large-10.jpg",
67     DEMO_IMAGE_DIR "gallery-large-11.jpg",
68     DEMO_IMAGE_DIR "gallery-large-12.jpg",
69     DEMO_IMAGE_DIR "gallery-large-13.jpg",
70     DEMO_IMAGE_DIR "gallery-large-14.jpg",
71     DEMO_IMAGE_DIR "gallery-large-15.jpg",
72     DEMO_IMAGE_DIR "gallery-large-16.jpg",
73     DEMO_IMAGE_DIR "gallery-large-17.jpg",
74     DEMO_IMAGE_DIR "gallery-large-18.jpg",
75     DEMO_IMAGE_DIR "gallery-large-19.jpg",
76     DEMO_IMAGE_DIR "gallery-large-20.jpg",
77     DEMO_IMAGE_DIR "gallery-large-21.jpg",
78 };
79 const int NUM_IMAGES(sizeof(IMAGES) / sizeof(IMAGES[0]));
80
81 // the number of cubes: NUM_COLUMNS*NUM_ROWS
82 // better choose the numbers that can divide viewAreaSize.x
83 const int NUM_COLUMNS_WAVE(16);
84 const int NUM_COLUMNS_CROSS(8);
85 const int NUM_COLUMNS_FOLD(8);
86 // better choose the numbers that can divide viewAreaSize.y
87 const int NUM_ROWS_WAVE(20);
88 const int NUM_ROWS_CROSS(10);
89 const int NUM_ROWS_FOLD(10);
90 //transition effect duration
91 const float ANIMATION_DURATION_WAVE(1.5f);
92 const float ANIMATION_DURATION_CROSS(1.f);
93 const float ANIMATION_DURATION_FOLD(1.f);
94 //transition effect displacement
95 const float CUBE_DISPLACEMENT_WAVE(70.f);
96 const float CUBE_DISPLACEMENT_CROSS(30.f);
97
98 // The duration of the current image staying on screen when slideshow is on
99 const int VIEWINGTIME = 2000; // 2 seconds
100
101 } // namespace
102
103 class CubeTransitionApp : public ConnectionTracker
104 {
105 public:
106   /**
107    * Constructor
108    * @param application class, stored as reference
109    */
110   CubeTransitionApp(Application& application);
111
112   ~CubeTransitionApp();
113
114 private:
115   /**
116    * This method gets called once the main loop of application is up and running
117    */
118   void OnInit(Application& application);
119   /**
120    * PanGesture callback. This method gets called when the pan gesture is detected.
121    * @param[in] actor The actor receiving the pan gesture.
122    * @param[in] gesture The detected pan gesture.
123    */
124   void OnPanGesture(Actor actor, const PanGesture& gesture);
125   /**
126    * Load the next image and start the transition;
127    */
128   void GoToNextImage();
129   /**
130    * Main key event handler
131    */
132   void OnKeyEvent(const KeyEvent& event);
133   /**
134    * Callback function of effect-switch button
135    * Change the effect when the effect button is clicked
136    * @param[in] button The handle of the clicked button
137    */
138   bool OnEffectButtonClicked(Toolkit::Button button);
139   /**
140    * Callback function of slideshow button
141    * Start or stop the automatical image display when the slideshow button is clicked
142    * @param[in] button The handle of the clicked button
143    */
144   bool OnSildeshowButtonClicked(Toolkit::Button button);
145   /**
146    * Callback function of cube transition completed signal
147    * @param[in] effect The cube effect used for the transition
148    * @param[in] texture The target Texture of the completed transition
149    */
150   void OnTransitionCompleted(Toolkit::CubeTransitionEffect effect, Texture image);
151   /**
152    * Callback function of timer tick
153    * The timer is used to count the image display duration in slideshow,
154    */
155   bool OnTimerTick();
156
157   /**
158    * Loads image, resizes it to the size of window and creates a textue out of it
159    * @param[in] filepath Path to the image file
160    * @return New texture object
161    */
162   Texture LoadWindowFillingTexture(const char* filepath);
163
164 private:
165   Application&       mApplication;
166   Toolkit::Control   mView;
167   Toolkit::ToolBar   mToolBar;
168   Layer              mContent;
169   Toolkit::TextLabel mTitle;
170
171   Vector2 mViewSize;
172
173   Texture      mCurrentTexture;
174   Texture      mNextTexture;
175   unsigned int mIndex;
176   bool         mIsImageLoading;
177
178   PanGestureDetector mPanGestureDetector;
179
180   Toolkit::CubeTransitionEffect mCubeWaveEffect;
181   Toolkit::CubeTransitionEffect mCubeCrossEffect;
182   Toolkit::CubeTransitionEffect mCubeFoldEffect;
183   Toolkit::CubeTransitionEffect mCurrentEffect;
184
185   bool                mSlideshow;
186   Timer               mViewTimer;
187   Toolkit::PushButton mSlideshowButton;
188
189   Vector2 mPanPosition;
190   Vector2 mPanDisplacement;
191 };
192
193 CubeTransitionApp::CubeTransitionApp(Application& application)
194 : mApplication(application),
195   mIndex(0),
196   mIsImageLoading(false),
197   mSlideshow(false)
198 {
199   mApplication.InitSignal().Connect(this, &CubeTransitionApp::OnInit);
200 }
201
202 CubeTransitionApp::~CubeTransitionApp()
203 {
204   //Nothing to do
205 }
206
207 void CubeTransitionApp::OnInit(Application& application)
208 {
209   application.GetWindow().KeyEventSignal().Connect(this, &CubeTransitionApp::OnKeyEvent);
210
211   // Creates a default view with a default tool bar, the view is added to the window.
212   mContent = DemoHelper::CreateView(application, mView, mToolBar, "", TOOLBAR_IMAGE, "");
213   mContent.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
214
215   // Add an effect changing toggle button
216   Toolkit::ToggleButton effectChangeToggleButton = Toolkit::ToggleButton::ToggleButton::New();
217
218   effectChangeToggleButton.SetProperty(Toolkit::ToggleButton::Property::STATE_VISUALS,
219                                        Property::Array{EFFECT_WAVE_IMAGE,
220                                                        EFFECT_CROSS_IMAGE,
221                                                        EFFECT_FOLD_IMAGE});
222
223   effectChangeToggleButton.ClickedSignal().Connect(this, &CubeTransitionApp::OnEffectButtonClicked);
224   mToolBar.AddControl(effectChangeToggleButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
225
226   // Add title to the tool bar.
227   mTitle = DemoHelper::CreateToolBarLabel(APPLICATION_TITLE_WAVE);
228   mToolBar.AddControl(mTitle, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Toolkit::Alignment::HORIZONTAL_CENTER);
229
230   //Add an slideshow icon on the right of the title
231   mSlideshowButton = Toolkit::PushButton::New();
232   mSlideshowButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_START_ICON);
233   mSlideshowButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_START_ICON_SELECTED);
234   mSlideshowButton.ClickedSignal().Connect(this, &CubeTransitionApp::OnSildeshowButtonClicked);
235   mToolBar.AddControl(mSlideshowButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_CENTER, DemoHelper::DEFAULT_PLAY_PADDING);
236
237   // Set size to window size to avoid seeing a black border on transition
238   mViewSize = application.GetWindow().GetSize();
239
240   // show the first image
241   mCurrentTexture = LoadWindowFillingTexture(IMAGES[mIndex]);
242
243   //use small cubes
244   mCubeWaveEffect = Toolkit::CubeTransitionWaveEffect::New(NUM_ROWS_WAVE, NUM_COLUMNS_WAVE);
245   mCubeWaveEffect.SetTransitionDuration(ANIMATION_DURATION_WAVE);
246   mCubeWaveEffect.SetCubeDisplacement(CUBE_DISPLACEMENT_WAVE);
247   mCubeWaveEffect.TransitionCompletedSignal().Connect(this, &CubeTransitionApp::OnTransitionCompleted);
248
249   mCubeWaveEffect.SetProperty(Actor::Property::SIZE, mViewSize);
250   mCubeWaveEffect.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
251   mCubeWaveEffect.SetCurrentTexture(mCurrentTexture);
252
253   // use big cubes
254   mCubeCrossEffect = Toolkit::CubeTransitionCrossEffect::New(NUM_ROWS_CROSS, NUM_COLUMNS_CROSS);
255   mCubeCrossEffect.SetTransitionDuration(ANIMATION_DURATION_CROSS);
256   mCubeCrossEffect.SetCubeDisplacement(CUBE_DISPLACEMENT_CROSS);
257   mCubeCrossEffect.TransitionCompletedSignal().Connect(this, &CubeTransitionApp::OnTransitionCompleted);
258
259   mCubeCrossEffect.SetProperty(Actor::Property::SIZE, mViewSize);
260   mCubeCrossEffect.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
261   mCubeCrossEffect.SetCurrentTexture(mCurrentTexture);
262
263   mCubeFoldEffect = Toolkit::CubeTransitionFoldEffect::New(NUM_ROWS_FOLD, NUM_COLUMNS_FOLD);
264   mCubeFoldEffect.SetTransitionDuration(ANIMATION_DURATION_FOLD);
265   mCubeFoldEffect.TransitionCompletedSignal().Connect(this, &CubeTransitionApp::OnTransitionCompleted);
266
267   mCubeFoldEffect.SetProperty(Actor::Property::SIZE, mViewSize);
268   mCubeFoldEffect.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
269   mCubeFoldEffect.SetCurrentTexture(mCurrentTexture);
270
271   mViewTimer = Timer::New(VIEWINGTIME);
272   mViewTimer.TickSignal().Connect(this, &CubeTransitionApp::OnTimerTick);
273
274   mCurrentEffect = mCubeWaveEffect;
275   mContent.Add(mCurrentEffect);
276
277   // use pan gesture to detect the cursor or finger movement
278   mPanGestureDetector = PanGestureDetector::New();
279   mPanGestureDetector.DetectedSignal().Connect(this, &CubeTransitionApp::OnPanGesture);
280   mPanGestureDetector.Attach(mContent);
281 }
282
283 // signal handler, called when the pan gesture is detected
284 void CubeTransitionApp::OnPanGesture(Actor actor, const PanGesture& gesture)
285 {
286   // does not response when the transition has not finished
287   if(mIsImageLoading || mCubeWaveEffect.IsTransitioning() || mCubeCrossEffect.IsTransitioning() || mCubeFoldEffect.IsTransitioning() || mSlideshow)
288   {
289     return;
290   }
291
292   if(gesture.GetState() == GestureState::CONTINUING)
293   {
294     const Vector2& displacement = gesture.GetDisplacement();
295     if(displacement.x < 0)
296     {
297       mIndex = (mIndex + 1) % NUM_IMAGES;
298     }
299     else
300     {
301       mIndex = (mIndex + NUM_IMAGES - 1) % NUM_IMAGES;
302     }
303
304     mPanPosition     = gesture.GetPosition();
305     mPanDisplacement = displacement;
306     GoToNextImage();
307   }
308 }
309
310 void CubeTransitionApp::GoToNextImage()
311 {
312   mNextTexture = LoadWindowFillingTexture(IMAGES[mIndex]);
313   mCurrentEffect.SetTargetTexture(mNextTexture);
314   mIsImageLoading = false;
315   mCurrentEffect.StartTransition(mPanPosition, mPanDisplacement);
316   mCurrentTexture = mNextTexture;
317 }
318
319 bool CubeTransitionApp::OnEffectButtonClicked(Toolkit::Button button)
320 {
321   mContent.Remove(mCurrentEffect);
322   if(mCurrentEffect == mCubeWaveEffect)
323   {
324     mCurrentEffect = mCubeCrossEffect;
325     mTitle.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_CROSS));
326   }
327   else if(mCurrentEffect == mCubeCrossEffect)
328   {
329     mCurrentEffect = mCubeFoldEffect;
330     mTitle.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_FOLD));
331   }
332   else
333   {
334     mCurrentEffect = mCubeWaveEffect;
335     mTitle.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_WAVE));
336   }
337   mContent.Add(mCurrentEffect);
338
339   // Set the current image to cube transition effect
340   // only need to set at beginning or change from another effect
341   mCurrentEffect.SetCurrentTexture(mCurrentTexture);
342   return true;
343 }
344
345 bool CubeTransitionApp::OnSildeshowButtonClicked(Toolkit::Button button)
346 {
347   mSlideshow = !mSlideshow;
348   if(mSlideshow)
349   {
350     mPanGestureDetector.Detach(mContent);
351     mSlideshowButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_STOP_ICON);
352     mSlideshowButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_STOP_ICON_SELECTED);
353     mPanPosition     = Vector2(mViewSize.width, mViewSize.height * 0.5f);
354     mPanDisplacement = Vector2(-10.f, 0.f);
355     mViewTimer.Start();
356   }
357   else
358   {
359     mPanGestureDetector.Attach(mContent);
360     mSlideshowButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_START_ICON);
361     mSlideshowButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, SLIDE_SHOW_START_ICON_SELECTED);
362     mViewTimer.Stop();
363   }
364   return true;
365 }
366
367 void CubeTransitionApp::OnTransitionCompleted(Toolkit::CubeTransitionEffect effect, Texture texture)
368 {
369   if(mSlideshow)
370   {
371     mViewTimer.Start();
372   }
373 }
374
375 bool CubeTransitionApp::OnTimerTick()
376 {
377   if(mSlideshow)
378   {
379     mIndex = (mIndex + 1) % NUM_IMAGES;
380     GoToNextImage();
381   }
382
383   //return false to stop the timer
384   return false;
385 }
386
387 Texture CubeTransitionApp::LoadWindowFillingTexture(const char* filepath)
388 {
389   ImageDimensions    dimensions(mApplication.GetWindow().GetSize());
390   Devel::PixelBuffer pixelBuffer = LoadImageFromFile(filepath, dimensions, FittingMode::SCALE_TO_FILL);
391   PixelData          pixelData   = Devel::PixelBuffer::Convert(pixelBuffer);
392
393   Texture texture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
394   texture.Upload(pixelData);
395   return texture;
396 }
397
398 void CubeTransitionApp::OnKeyEvent(const KeyEvent& event)
399 {
400   if(event.GetState() == 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 int DALI_EXPORT_API main(int argc, char** argv)
410 {
411   Application       application = Application::New(&argc, &argv, DEMO_THEME_PATH);
412   CubeTransitionApp test(application);
413   application.MainLoop();
414
415   return 0;
416 }