2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
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");
35 const char* BACKGROUND_IMAGES[] =
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",
43 const unsigned int NUM_BACKGROUND_IMAGES(sizeof(BACKGROUND_IMAGES) / sizeof(BACKGROUND_IMAGES[0]));
45 const char* BUBBLE_SHAPE_IMAGES[] =
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]));
53 const Vector2 DEFAULT_BUBBLE_SIZE(10.f, 30.f);
54 const unsigned int DEFAULT_NUMBER_OF_BUBBLES(1000);
58 // This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the window.
59 class BubbleEffectExample : public ConnectionTracker
62 BubbleEffectExample(Application& app)
67 mChangeBackgroundButton(),
68 mChangeBubbleShapeButton(),
69 mTimerForBubbleEmission(),
70 mHSVDelta(Vector3(0.f, 0.f, 0.5f)),
71 mCurrentTouchPosition(),
73 mAnimateComponentCount(0),
76 mCurrentBackgroundImageId(0),
77 mCurrentBubbleShapeImageId(0),
78 mNeedNewAnimation(true)
80 // Connect to the Application's Init signal
81 app.InitSignal().Connect(this, &BubbleEffectExample::Create);
84 ~BubbleEffectExample()
89 // The Init signal is received once (only) during the Application lifetime
90 void Create(Application& app)
92 Window window = app.GetWindow();
93 Vector2 windowSize = window.GetSize();
95 window.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
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,
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);
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);
132 mBubbleEmitter.SetBackground(DemoHelper::LoadWindowFillingTexture(window.GetSize(), BACKGROUND_IMAGES[mCurrentBackgroundImageId]), mHSVDelta);
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);
140 // Set the application background
141 mBackground.SetProperty(Toolkit::Control::Property::BACKGROUND, BACKGROUND_IMAGES[mCurrentBackgroundImageId]);
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);
147 // Connect the callback to the touch signal on the background
148 mBackground.TouchedSignal().Connect(this, &BubbleEffectExample::OnTouch);
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)
158 if(mNeedNewAnimation)
160 float duration = Random::Range(1.f, 1.5f);
161 mEmitAnimation = Animation::New(duration);
162 mNeedNewAnimation = false;
163 mAnimateComponentCount = 0;
166 mBubbleEmitter.EmitBubble(mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600));
168 mAnimateComponentCount++;
170 if(mAnimateComponentCount % 4 == 0)
172 mEmitAnimation.Play();
173 mNeedNewAnimation = true;
177 // Emit bubbles when the finger touches down but keep stationary.
178 // And stops emitting new bubble after being stationary for 2 seconds
181 if(mEmitPosition == mCurrentTouchPosition) // finger is not moving
184 if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds
186 for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick
188 SetUpAnimation(mCurrentTouchPosition + Vector2(rand() % 5, rand() % 5), Vector2(rand() % 60 - 30, rand() % 100 - 50));
194 mNonMovementCount = 0;
195 mEmitPosition = mCurrentTouchPosition;
201 // Callback function of the touch signal on the background
202 bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event)
204 switch(event.GetState(0))
206 case PointState::DOWN:
208 mCurrentTouchPosition = mEmitPosition = event.GetScreenPosition(0);
209 mTimerForBubbleEmission.Start();
210 mNonMovementCount = 0;
214 case PointState::MOTION:
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)
222 SetUpAnimation(mCurrentTouchPosition + displacement * (i / step), displacement);
227 case PointState::LEAVE:
228 case PointState::INTERRUPTED:
230 mTimerForBubbleEmission.Stop();
231 mEmitAnimation.Play();
232 mNeedNewAnimation = true;
233 mAnimateComponentCount = 0;
236 case PointState::STATIONARY:
245 bool OnChangeIconClicked(Toolkit::Button button)
247 if(button == mChangeBackgroundButton)
249 mCurrentBackgroundImageId = (mCurrentBackgroundImageId + 1) % NUM_BACKGROUND_IMAGES;
251 //Update bubble emitter background
252 mBubbleEmitter.SetBackground(DemoHelper::LoadWindowFillingTexture(mApp.GetWindow().GetSize(), BACKGROUND_IMAGES[mCurrentBackgroundImageId]), mHSVDelta);
254 // Set the application background
255 mBackground.SetProperty(Toolkit::Control::Property::BACKGROUND, BACKGROUND_IMAGES[mCurrentBackgroundImageId]);
257 else if(button == mChangeBubbleShapeButton)
259 mBubbleEmitter.SetBubbleShape(DemoHelper::LoadTexture(BUBBLE_SHAPE_IMAGES[++mCurrentBubbleShapeImageId % NUM_BUBBLE_SHAPE_IMAGES]));
265 * Main key event handler
267 void OnKeyEvent(const KeyEvent& event)
269 if(event.GetState() == KeyEvent::DOWN)
271 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
280 Dali::Toolkit::Control mBackground;
282 Toolkit::BubbleEmitter mBubbleEmitter;
283 Animation mEmitAnimation;
284 Toolkit::PushButton mChangeBackgroundButton;
285 Toolkit::PushButton mChangeBubbleShapeButton;
286 Timer mTimerForBubbleEmission;
289 Vector2 mCurrentTouchPosition;
290 Vector2 mEmitPosition;
292 unsigned int mAnimateComponentCount;
293 unsigned int mNonMovementCount;
294 unsigned int mTimerInterval;
295 unsigned int mCurrentBackgroundImageId;
296 unsigned int mCurrentBubbleShapeImageId;
298 bool mNeedNewAnimation;
301 /*****************************************************************************/
303 int DALI_EXPORT_API main(int argc, char** argv)
305 Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
306 BubbleEffectExample theApp(app);