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