Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / bubble-effect / bubble-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 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h>
20 #include <dali/dali.h>
21 #include "shared/utility.h"
22 #include "shared/view.h"
23
24 using namespace Dali;
25
26 namespace
27 {
28 const char* const TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
29 const char* const APPLICATION_TITLE("Bubble Effect");
30 const char* const CHANGE_BACKGROUND_ICON(DEMO_IMAGE_DIR "icon-change.png");
31 const char* const CHANGE_BACKGROUND_ICON_SELECTED(DEMO_IMAGE_DIR "icon-change-selected.png");
32 const char* const CHANGE_BUBBLE_SHAPE_ICON(DEMO_IMAGE_DIR "icon-replace.png");
33 const char* const CHANGE_BUBBLE_SHAPE_ICON_SELECTED(DEMO_IMAGE_DIR "icon-replace-selected.png");
34
35 const char* BACKGROUND_IMAGES[] =
36   {
37     DEMO_IMAGE_DIR "background-1.jpg",
38     DEMO_IMAGE_DIR "background-2.jpg",
39     DEMO_IMAGE_DIR "background-3.jpg",
40     DEMO_IMAGE_DIR "background-4.jpg",
41     DEMO_IMAGE_DIR "background-5.jpg",
42 };
43 const unsigned int NUM_BACKGROUND_IMAGES(sizeof(BACKGROUND_IMAGES) / sizeof(BACKGROUND_IMAGES[0]));
44
45 const char* BUBBLE_SHAPE_IMAGES[] =
46   {
47     DEMO_IMAGE_DIR "bubble-ball.png",
48     DEMO_IMAGE_DIR "icon-effect-cross.png",
49     DEMO_IMAGE_DIR "icon-item-view-layout-spiral.png",
50     DEMO_IMAGE_DIR "icon-replace.png"};
51 const unsigned int NUM_BUBBLE_SHAPE_IMAGES(sizeof(BUBBLE_SHAPE_IMAGES) / sizeof(BUBBLE_SHAPE_IMAGES[0]));
52
53 const Vector2      DEFAULT_BUBBLE_SIZE(10.f, 30.f);
54 const unsigned int DEFAULT_NUMBER_OF_BUBBLES(1000);
55
56 } // namespace
57
58 // This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the window.
59 class BubbleEffectExample : public ConnectionTracker
60 {
61 public:
62   BubbleEffectExample(Application& app)
63   : mApp(app),
64     mBackground(),
65     mBubbleEmitter(),
66     mEmitAnimation(),
67     mChangeBackgroundButton(),
68     mChangeBubbleShapeButton(),
69     mTimerForBubbleEmission(),
70     mHSVDelta(Vector3(0.f, 0.f, 0.5f)),
71     mCurrentTouchPosition(),
72     mEmitPosition(),
73     mAnimateComponentCount(0),
74     mNonMovementCount(0),
75     mTimerInterval(16),
76     mCurrentBackgroundImageId(0),
77     mCurrentBubbleShapeImageId(0),
78     mNeedNewAnimation(true)
79   {
80     // Connect to the Application's Init signal
81     app.InitSignal().Connect(this, &BubbleEffectExample::Create);
82   }
83
84   ~BubbleEffectExample()
85   {
86   }
87
88 private:
89   // The Init signal is received once (only) during the Application lifetime
90   void Create(Application& app)
91   {
92     Window  window     = app.GetWindow();
93     Vector2 windowSize = window.GetSize();
94
95     window.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
96
97     // Creates a default view with a default tool bar.
98     // The view is added to the window.
99     Toolkit::ToolBar toolBar;
100     Layer            content = DemoHelper::CreateView(app,
101                                            mBackground,
102                                            toolBar,
103                                            "",
104                                            TOOLBAR_IMAGE,
105                                            APPLICATION_TITLE);
106
107     // Add a button to change background. (right of toolbar)
108     mChangeBackgroundButton = Toolkit::PushButton::New();
109     mChangeBackgroundButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, CHANGE_BACKGROUND_ICON);
110     mChangeBackgroundButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, CHANGE_BACKGROUND_ICON_SELECTED);
111     mChangeBackgroundButton.ClickedSignal().Connect(this, &BubbleEffectExample::OnChangeIconClicked);
112     toolBar.AddControl(mChangeBackgroundButton,
113                        DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
114                        Toolkit::Alignment::HORIZONTAL_RIGHT,
115                        DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
116     // Add a button to change bubble shape. ( left of bar )
117     mChangeBubbleShapeButton = Toolkit::PushButton::New();
118     mChangeBubbleShapeButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, CHANGE_BUBBLE_SHAPE_ICON);
119     mChangeBubbleShapeButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, CHANGE_BUBBLE_SHAPE_ICON_SELECTED);
120     mChangeBubbleShapeButton.ClickedSignal().Connect(this, &BubbleEffectExample::OnChangeIconClicked);
121     toolBar.AddControl(mChangeBubbleShapeButton,
122                        DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
123                        Toolkit::Alignment::HORIZONTAL_LEFT,
124                        DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
125
126     // Create and initialize the BubbleEmitter object
127     mBubbleEmitter = Toolkit::BubbleEmitter::New(windowSize,
128                                                  DemoHelper::LoadTexture(BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId]),
129                                                  DEFAULT_NUMBER_OF_BUBBLES,
130                                                  DEFAULT_BUBBLE_SIZE);
131
132     mBubbleEmitter.SetBackground(DemoHelper::LoadWindowFillingTexture(window.GetSize(), BACKGROUND_IMAGES[mCurrentBackgroundImageId]), mHSVDelta);
133
134     // Get the root actor of all bubbles, and add it to window.
135     Actor bubbleRoot = mBubbleEmitter.GetRootActor();
136     bubbleRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
137     bubbleRoot.SetProperty(Actor::Property::POSITION_Z, 0.1f); // Make sure the bubbles displayed on top og the background.
138     content.Add(bubbleRoot);
139
140     // Set the application background
141     mBackground.SetProperty(Toolkit::Control::Property::BACKGROUND, BACKGROUND_IMAGES[mCurrentBackgroundImageId]);
142
143     // Set up the timer to emit bubble regularly when the finger is touched down but not moved
144     mTimerForBubbleEmission = Timer::New(mTimerInterval);
145     mTimerForBubbleEmission.TickSignal().Connect(this, &BubbleEffectExample::OnTimerTick);
146
147     // Connect the callback to the touch signal on the background
148     mBackground.TouchedSignal().Connect(this, &BubbleEffectExample::OnTouch);
149   }
150
151   /***********
152  * Emit bubbles
153  *****************/
154
155   // Set up the animation of emitting bubbles, to be efficient, every animation controls multiple emission ( 4 here )
156   void SetUpAnimation(Vector2 emitPosition, Vector2 direction)
157   {
158     if(mNeedNewAnimation)
159     {
160       float duration         = Random::Range(1.f, 1.5f);
161       mEmitAnimation         = Animation::New(duration);
162       mNeedNewAnimation      = false;
163       mAnimateComponentCount = 0;
164     }
165
166     mBubbleEmitter.EmitBubble(mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600));
167
168     mAnimateComponentCount++;
169
170     if(mAnimateComponentCount % 4 == 0)
171     {
172       mEmitAnimation.Play();
173       mNeedNewAnimation = true;
174     }
175   }
176
177   // Emit bubbles when the finger touches down but keep stationary.
178   // And stops emitting new bubble after being stationary for 2 seconds
179   bool OnTimerTick()
180   {
181     if(mEmitPosition == mCurrentTouchPosition) // finger is not moving
182     {
183       mNonMovementCount++;
184       if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds
185       {
186         for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick
187         {
188           SetUpAnimation(mCurrentTouchPosition + Vector2(rand() % 5, rand() % 5), Vector2(rand() % 60 - 30, rand() % 100 - 50));
189         }
190       }
191     }
192     else
193     {
194       mNonMovementCount = 0;
195       mEmitPosition     = mCurrentTouchPosition;
196     }
197
198     return true;
199   }
200
201   // Callback function of the touch signal on the background
202   bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event)
203   {
204     switch(event.GetState(0))
205     {
206       case PointState::DOWN:
207       {
208         mCurrentTouchPosition = mEmitPosition = event.GetScreenPosition(0);
209         mTimerForBubbleEmission.Start();
210         mNonMovementCount = 0;
211
212         break;
213       }
214       case PointState::MOTION:
215       {
216         Vector2 displacement  = event.GetScreenPosition(0) - mCurrentTouchPosition;
217         mCurrentTouchPosition = event.GetScreenPosition(0);
218         //emit multiple bubbles along the moving direction when the finger moves quickly
219         float step = std::min(5.f, displacement.Length());
220         for(float i = 0.25f; i < step; i = i + 1.f)
221         {
222           SetUpAnimation(mCurrentTouchPosition + displacement * (i / step), displacement);
223         }
224         break;
225       }
226       case PointState::UP:
227       case PointState::LEAVE:
228       case PointState::INTERRUPTED:
229       {
230         mTimerForBubbleEmission.Stop();
231         mEmitAnimation.Play();
232         mNeedNewAnimation      = true;
233         mAnimateComponentCount = 0;
234         break;
235       }
236       case PointState::STATIONARY:
237       default:
238       {
239         break;
240       }
241     }
242     return true;
243   }
244
245   bool OnChangeIconClicked(Toolkit::Button button)
246   {
247     if(button == mChangeBackgroundButton)
248     {
249       mCurrentBackgroundImageId = (mCurrentBackgroundImageId + 1) % NUM_BACKGROUND_IMAGES;
250
251       //Update bubble emitter background
252       mBubbleEmitter.SetBackground(DemoHelper::LoadWindowFillingTexture(mApp.GetWindow().GetSize(), BACKGROUND_IMAGES[mCurrentBackgroundImageId]), mHSVDelta);
253
254       // Set the application background
255       mBackground.SetProperty(Toolkit::Control::Property::BACKGROUND, BACKGROUND_IMAGES[mCurrentBackgroundImageId]);
256     }
257     else if(button == mChangeBubbleShapeButton)
258     {
259       mBubbleEmitter.SetBubbleShape(DemoHelper::LoadTexture(BUBBLE_SHAPE_IMAGES[++mCurrentBubbleShapeImageId % NUM_BUBBLE_SHAPE_IMAGES]));
260     }
261     return true;
262   }
263
264   /**
265    * Main key event handler
266    */
267   void OnKeyEvent(const KeyEvent& event)
268   {
269     if(event.GetState() == KeyEvent::DOWN)
270     {
271       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
272       {
273         mApp.Quit();
274       }
275     }
276   }
277
278 private:
279   Application&           mApp;
280   Dali::Toolkit::Control mBackground;
281
282   Toolkit::BubbleEmitter mBubbleEmitter;
283   Animation              mEmitAnimation;
284   Toolkit::PushButton    mChangeBackgroundButton;
285   Toolkit::PushButton    mChangeBubbleShapeButton;
286   Timer                  mTimerForBubbleEmission;
287
288   Vector3 mHSVDelta;
289   Vector2 mCurrentTouchPosition;
290   Vector2 mEmitPosition;
291
292   unsigned int mAnimateComponentCount;
293   unsigned int mNonMovementCount;
294   unsigned int mTimerInterval;
295   unsigned int mCurrentBackgroundImageId;
296   unsigned int mCurrentBubbleShapeImageId;
297
298   bool mNeedNewAnimation;
299 };
300
301 /*****************************************************************************/
302
303 int DALI_EXPORT_API main(int argc, char** argv)
304 {
305   Application         app = Application::New(&argc, &argv, DEMO_THEME_PATH);
306   BubbleEffectExample theApp(app);
307   app.MainLoop();
308   return 0;
309 }