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