Using migrated Public Visual API
[platform/core/uifw/dali-demo.git] / examples / animated-images / animated-images-example.cpp
1 /*
2  * Copyright (c) 2017 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/buttons/button-devel.h>
20 #include "shared/utility.h"
21
22 using namespace Dali;
23 using namespace Dali::Toolkit;
24
25 namespace
26 {
27 const char * const PLAY_ICON( DEMO_IMAGE_DIR "icon-play.png" );
28 const char * const PLAY_ICON_SELECTED( DEMO_IMAGE_DIR "icon-play-selected.png" );
29
30 const char* const STATIC_GIF_DOG( DEMO_IMAGE_DIR "dog-static.gif" );
31 const char* const ANIMATE_GIF_DOG( DEMO_IMAGE_DIR "dog-anim.gif" );
32
33 const char* const STATIC_GIF_LOGO( DEMO_IMAGE_DIR "dali-logo-static.gif" );
34 const char* const ANIMATE_GIF_LOGO( DEMO_IMAGE_DIR "dali-logo-anim.gif" );
35
36 const char* const ANIMATE_PIXEL_AREA( "Animate PixelArea" );
37 const char* const ANIMATE_PIXEL_AREA_AND_SCALE( "Animate PixelArea & Scale" );
38
39 const char* const STATIC_IMAGE_ARRAY_DOG( DEMO_IMAGE_DIR "dog-anim-001.png" );
40 const char* const ANIMATE_IMAGE_ARRAY_DOG( DEMO_IMAGE_DIR "dog-anim-%03d.png" );
41
42 const char* const STATIC_IMAGE_ARRAY_LOGO( DEMO_IMAGE_DIR "dali-logo-anim-001.png" );
43 const char* const ANIMATE_IMAGE_ARRAY_LOGO( DEMO_IMAGE_DIR "dali-logo-anim-%03d.png" );
44
45
46 const Vector4 DIM_COLOR( 0.85f, 0.85f, 0.85f, 0.85f );
47 }
48
49 /* This example shows how to display a GIF image.
50  * First a static GIF image is loaded and then when the user presses on the "Play" icon,
51  * the static image is replaced by an animated one
52  */
53
54 class AnimatedImageController : public ConnectionTracker
55 {
56 public:
57   enum ImageType
58   {
59     GIF,
60     IMAGE_ARRAY
61   };
62   enum StateType
63   {
64     STATIC,
65     ANIMATED
66   };
67
68   AnimatedImageController( Application& application )
69   : mApplication( application ),
70     mImageType(GIF)
71   {
72     // Connect to the Application's Init signal
73     mApplication.InitSignal().Connect( this, &AnimatedImageController::Create );
74   }
75
76   ~AnimatedImageController()
77   {
78     // Nothing to do here;
79   }
80
81   // The Init signal is received once (only) during the Application lifetime
82   void Create( Application& application )
83   {
84     // Get a handle to the stage
85     Stage stage = Stage::GetCurrent();
86     stage.SetBackgroundColor( Color::WHITE );
87     // Tie-in input event handlers:
88     stage.KeyEventSignal().Connect( this, &AnimatedImageController::OnKeyEvent );
89
90     CreateStaticImageView( 0 );
91     CreateStaticImageView( 1 );
92
93     mGifButton = Toolkit::RadioButton::New("Gif");
94     mGifButton.SetProperty( Button::Property::SELECTED, true );
95     mArrayButton = Toolkit::RadioButton::New("Array");
96     mGifButton.ClickedSignal().Connect( this, &AnimatedImageController::OnTypeButtonClicked );
97     mArrayButton.ClickedSignal().Connect( this, &AnimatedImageController::OnTypeButtonClicked );
98
99     Toolkit::TableView radioButtonLayout = Toolkit::TableView::New(1, 2);
100     radioButtonLayout.SetName("RadioButtonsLayout");
101     radioButtonLayout.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
102     radioButtonLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
103     radioButtonLayout.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
104     radioButtonLayout.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
105     radioButtonLayout.SetFitHeight(0);
106     radioButtonLayout.AddChild( mGifButton, TableView::CellPosition(0,0) );
107     radioButtonLayout.AddChild( mArrayButton, TableView::CellPosition(0,1) );
108     radioButtonLayout.SetCellAlignment( TableView::CellPosition( 0, 0 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
109     radioButtonLayout.SetCellAlignment( TableView::CellPosition( 0, 1 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
110     radioButtonLayout.SetY( -10.0f );
111
112     stage.Add( radioButtonLayout );
113
114     mTapDetector = TapGestureDetector::New();
115     mTapDetector.DetectedSignal().Connect( this, &AnimatedImageController::OnTap );
116   }
117
118   void CreateStaticImageView( int index )
119   {
120     Actor& actor = (index==0) ? mActorDog : mActorLogo;
121
122     Stage stage = Stage::GetCurrent();
123     if( actor )
124     {
125       stage.Remove( actor );
126     }
127
128     Property::Value viewSetup = SetupViewProperties( mImageType, STATIC, index, false );
129     actor = CreateImageViewWithPlayButton( viewSetup );
130     SetLayout(actor, index);
131     stage.Add( actor );
132   }
133
134
135   void CreateAnimImageView( int index )
136   {
137     Actor& actor = (index==0) ? mActorDog : mActorLogo;
138
139     Stage stage = Stage::GetCurrent();
140     if( actor )
141     {
142       stage.Remove( actor );
143     }
144
145     const char* label = (index==0) ? ANIMATE_PIXEL_AREA_AND_SCALE : ANIMATE_PIXEL_AREA;
146
147     Property::Value viewSetup = SetupViewProperties( mImageType, ANIMATED, index, true );
148     actor = CreateImageViewWithAnimatePixelAreaButton( viewSetup, label);
149     SetLayout(actor, index);
150
151     stage.Add( actor );
152   }
153
154   void SetLayout( Actor actor, int index )
155   {
156     if( index == 0 )
157     {
158       actor.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
159       actor.SetY( -80.f );
160     }
161     else
162     {
163       actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
164       actor.SetY( 80.f );
165     }
166   }
167
168   /**
169    * Create the gif image view with an overlay play button.
170    */
171   Toolkit::ImageView CreateImageViewWithPlayButton( Property::Value& viewSetup )
172   {
173     Toolkit::ImageView imageView = Toolkit::ImageView::New();
174     imageView.SetProperty( ImageView::Property::IMAGE, viewSetup );
175     imageView.SetParentOrigin( ParentOrigin::CENTER );
176
177     // Create a push button, and add it as child of the image view
178     Toolkit::PushButton animateButton = Toolkit::PushButton::New();
179     animateButton.SetProperty( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, PLAY_ICON );
180     animateButton.SetProperty( Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL, PLAY_ICON_SELECTED );
181     animateButton.SetParentOrigin( ParentOrigin::CENTER );
182     animateButton.SetAnchorPoint( AnchorPoint::CENTER );
183     animateButton.ClickedSignal().Connect( this, &AnimatedImageController::OnPlayButtonClicked );
184     imageView.Add( animateButton );
185
186     // Apply dim color on the gif view and the play button
187     imageView.SetColor( DIM_COLOR );
188
189     return imageView;
190   }
191
192   Toolkit::ImageView CreateImageViewWithAnimatePixelAreaButton( Property::Value& viewSetup, const std::string& buttonLabel )
193   {
194     Toolkit::ImageView imageView = Toolkit::ImageView::New();
195     imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, viewSetup );
196     imageView.SetParentOrigin( ParentOrigin::CENTER );
197
198     // Create a push button, and add it as child of the image view
199     Toolkit::PushButton animateButton = Toolkit::PushButton::New();
200     animateButton.SetProperty( Toolkit::Button::Property::LABEL, buttonLabel );
201     animateButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
202     animateButton.SetAnchorPoint( AnchorPoint::TOP_CENTER );
203     animateButton.SetY( 20.f );
204
205     animateButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
206     animateButton.SetProperty( Actor::Property::INHERIT_SCALE, false );
207     imageView.Add( animateButton );
208
209     mTapDetector.Attach( animateButton );
210     mTapDetector.Attach( imageView );
211
212     return imageView;
213   }
214
215   bool OnPlayButtonClicked( Toolkit::Button button )
216   {
217     Stage stage = Stage::GetCurrent();
218
219     // With play button clicked, the static gif is replaced with animated gif.
220     if( button.GetParent() ==  mActorDog )
221     {
222       // remove the static gif view, the play button is also removed as its child.
223       CreateAnimImageView( 0 );
224     }
225     else // button.GetParent() ==  mActorLogo
226     {
227       // remove the static gif view, the play button is also removed as its child.
228       CreateAnimImageView( 1 );
229     }
230     return true;
231   }
232
233   void OnTap(Dali::Actor actor, const Dali::TapGesture& tap)
234   {
235     if( actor.GetParent() ==  mActorDog ) // "Animate Pixel Area" button is clicked
236     {
237       Animation animation = Animation::New( 3.f );
238       animation.AnimateTo( Property( mActorDog, ImageView::Property::PIXEL_AREA ), Vector4( -1.0, 0.0, 3.f, 1.f ), AlphaFunction::SIN );
239       animation.AnimateTo( Property( mActorDog, Actor::Property::SCALE_X ), 3.f, AlphaFunction::SIN );
240       animation.Play();
241     }
242     else if( actor.GetParent() ==  mActorLogo ) // "Animate Pixel Area" button is clicked
243     {
244       Animation animation = Animation::New( 3.f );
245       animation.AnimateTo( Property( mActorLogo, ImageView::Property::PIXEL_AREA ), Vector4( 0.0, 1.0, 1.f, 1.f ), AlphaFunction::SIN );
246       animation.Play();
247     }
248     else if( actor == mActorDog ) // stop the animated gif, switch to static view
249     {
250       CreateStaticImageView( 0 );
251     }
252     else if( actor == mActorLogo ) // stop the animated gif, switch to static view
253     {
254       CreateStaticImageView( 1 );
255     }
256   }
257
258   bool OnTypeButtonClicked( Toolkit::Button button )
259   {
260     if( button == mGifButton )
261     {
262       mImageType = GIF;
263     }
264     else
265     {
266       mImageType = IMAGE_ARRAY;
267     }
268     Stage stage = Stage::GetCurrent();
269     CreateStaticImageView( 0 );
270     CreateStaticImageView( 1 );
271     return true;
272   }
273
274   void OnKeyEvent(const KeyEvent& event)
275   {
276     if(event.state == KeyEvent::Down)
277     {
278       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
279       {
280         mApplication.Quit();
281       }
282     }
283   }
284
285   Property::Value SetupViewProperties( ImageType type, StateType state, int index, bool wrap )
286   {
287     Property::Map map;
288
289     AddUrl( map, type, state, index );
290     AddWrap( map, wrap && state != 0, index );
291     AddCache( map, type, index );
292     return Property::Value(map);
293   }
294
295   void AddUrl( Property::Map& map, ImageType type, StateType state, int index )
296   {
297     const char* urls[2][2] =
298       { { STATIC_GIF_DOG, STATIC_GIF_LOGO },
299         { ANIMATE_GIF_DOG, ANIMATE_GIF_LOGO }
300       };
301     const char* urlFormats[2][2] =
302       { { STATIC_IMAGE_ARRAY_DOG, STATIC_IMAGE_ARRAY_LOGO } ,
303         { ANIMATE_IMAGE_ARRAY_DOG, ANIMATE_IMAGE_ARRAY_LOGO } };
304
305     int numFrames[2] = { 8, 15 };
306
307     if( type == GIF )
308     {
309       map.Add( Toolkit::ImageVisual::Property::URL, Property::Value( urls[state][index] ) );
310     }
311     else
312     {
313       if( state == STATIC )
314       {
315         Property::Array frameUrls;
316         frameUrls.Add(Property::Value( urlFormats[0][index] ));
317         map.Add( Toolkit::ImageVisual::Property::URL, frameUrls );
318       }
319       else
320       {
321         Property::Array frameUrls;
322         for( int i=1; i<= numFrames[index]; ++i )
323         {
324           char* buffer;
325           int len = asprintf( &buffer, urlFormats[1][index], i);
326           if( len > 0 )
327           {
328             std::string frameUrl(buffer);
329             free(buffer);
330             frameUrls.Add( Property::Value( frameUrl ) );
331           }
332         }
333         map.Add( Toolkit::ImageVisual::Property::URL, Property::Value( frameUrls ) );
334       }
335     }
336   }
337
338   void AddWrap( Property::Map& map, bool wrap, int index )
339   {
340     WrapMode::Type wrapModes[2][2] = {
341       { WrapMode::REPEAT, WrapMode::DEFAULT  },
342       { WrapMode::DEFAULT, WrapMode::MIRRORED_REPEAT } };
343
344     if( wrap )
345     {
346       map
347         .Add( Toolkit::ImageVisual::Property::WRAP_MODE_U, wrapModes[index][0] )
348         .Add( Toolkit::ImageVisual::Property::WRAP_MODE_V, wrapModes[index][1] );
349     }
350     else
351     {
352       map
353         .Add( Toolkit::ImageVisual::Property::WRAP_MODE_U, WrapMode::DEFAULT )
354         .Add( Toolkit::ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT );
355     }
356   }
357
358   void AddCache( Property::Map& map, ImageType type, int index )
359   {
360     if( type == IMAGE_ARRAY )
361     {
362       map
363         .Add( Toolkit::ImageVisual::Property::BATCH_SIZE, 4 )
364         .Add( Toolkit::ImageVisual::Property::CACHE_SIZE, 10 )
365         .Add( Toolkit::ImageVisual::Property::FRAME_DELAY, 150 );
366     }
367   }
368
369 private:
370   Application&  mApplication;
371   Toolkit::ImageView mActorDog;
372   Toolkit::ImageView mActorLogo;
373   Toolkit::RadioButton mGifButton;
374   Toolkit::RadioButton mArrayButton;
375   TapGestureDetector mTapDetector;
376   ImageType mImageType;
377 };
378
379 // Entry point for Linux & Tizen applications
380 //
381 int DALI_EXPORT_API main( int argc, char **argv )
382 {
383   Application application = Application::New( &argc, &argv );
384
385   AnimatedImageController test( application );
386
387   application.MainLoop();
388
389   return 0;
390 }