2 * Copyright (c) 2015 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.
22 #include "shared/view.h"
23 #include <dali/dali.h>
24 #include <dali-toolkit/dali-toolkit.h>
27 using namespace Dali::Toolkit;
31 const char * const BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-default.png" );
32 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
33 const char * const APPLICATION_TITLE( "ScrollView" );
34 const char * const EFFECT_CAROUSEL_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-carousel.png" );
35 const char * const EFFECT_CAROUSEL_IMAGE_SELECTED( DALI_IMAGE_DIR "icon-scroll-view-carousel-selected.png" );
37 const Vector3 ICON_SIZE(100.0f, 100.0f, 0.0f);
39 const char* EFFECT_MODE_NAME[] = {
46 const char * const IMAGE_PATHS[] = {
47 DALI_IMAGE_DIR "gallery-medium-1.jpg",
48 DALI_IMAGE_DIR "gallery-medium-2.jpg",
49 DALI_IMAGE_DIR "gallery-medium-3.jpg",
50 DALI_IMAGE_DIR "gallery-medium-4.jpg",
51 DALI_IMAGE_DIR "gallery-medium-5.jpg",
52 DALI_IMAGE_DIR "gallery-medium-6.jpg",
53 DALI_IMAGE_DIR "gallery-medium-7.jpg",
54 DALI_IMAGE_DIR "gallery-medium-8.jpg",
55 DALI_IMAGE_DIR "gallery-medium-9.jpg",
56 DALI_IMAGE_DIR "gallery-medium-10.jpg",
57 DALI_IMAGE_DIR "gallery-medium-11.jpg",
58 DALI_IMAGE_DIR "gallery-medium-12.jpg",
59 DALI_IMAGE_DIR "gallery-medium-13.jpg",
60 DALI_IMAGE_DIR "gallery-medium-14.jpg",
61 DALI_IMAGE_DIR "gallery-medium-15.jpg",
62 DALI_IMAGE_DIR "gallery-medium-16.jpg",
63 DALI_IMAGE_DIR "gallery-medium-17.jpg",
64 DALI_IMAGE_DIR "gallery-medium-18.jpg",
65 DALI_IMAGE_DIR "gallery-medium-19.jpg",
66 DALI_IMAGE_DIR "gallery-medium-20.jpg",
67 DALI_IMAGE_DIR "gallery-medium-21.jpg",
68 DALI_IMAGE_DIR "gallery-medium-22.jpg",
69 DALI_IMAGE_DIR "gallery-medium-23.jpg",
70 DALI_IMAGE_DIR "gallery-medium-24.jpg",
71 DALI_IMAGE_DIR "gallery-medium-25.jpg",
72 DALI_IMAGE_DIR "gallery-medium-26.jpg",
73 DALI_IMAGE_DIR "gallery-medium-27.jpg",
74 DALI_IMAGE_DIR "gallery-medium-28.jpg",
75 DALI_IMAGE_DIR "gallery-medium-29.jpg",
76 DALI_IMAGE_DIR "gallery-medium-30.jpg",
77 DALI_IMAGE_DIR "gallery-medium-31.jpg",
78 DALI_IMAGE_DIR "gallery-medium-32.jpg",
79 DALI_IMAGE_DIR "gallery-medium-33.jpg",
80 DALI_IMAGE_DIR "gallery-medium-34.jpg",
81 DALI_IMAGE_DIR "gallery-medium-35.jpg",
82 DALI_IMAGE_DIR "gallery-medium-36.jpg",
83 DALI_IMAGE_DIR "gallery-medium-37.jpg",
84 DALI_IMAGE_DIR "gallery-medium-38.jpg",
85 DALI_IMAGE_DIR "gallery-medium-39.jpg",
86 DALI_IMAGE_DIR "gallery-medium-40.jpg",
87 DALI_IMAGE_DIR "gallery-medium-41.jpg",
88 DALI_IMAGE_DIR "gallery-medium-42.jpg",
89 DALI_IMAGE_DIR "gallery-medium-43.jpg",
90 DALI_IMAGE_DIR "gallery-medium-44.jpg",
91 DALI_IMAGE_DIR "gallery-medium-45.jpg",
92 DALI_IMAGE_DIR "gallery-medium-46.jpg",
93 DALI_IMAGE_DIR "gallery-medium-47.jpg",
94 DALI_IMAGE_DIR "gallery-medium-48.jpg",
95 DALI_IMAGE_DIR "gallery-medium-49.jpg",
96 DALI_IMAGE_DIR "gallery-medium-50.jpg",
97 DALI_IMAGE_DIR "gallery-medium-51.jpg",
98 DALI_IMAGE_DIR "gallery-medium-52.jpg",
99 DALI_IMAGE_DIR "gallery-medium-53.jpg",
104 const char * const GetNextImagePath()
106 static const char * const * imagePtr = &IMAGE_PATHS[0];
108 if ( *(++imagePtr) == NULL )
110 imagePtr = &IMAGE_PATHS[0];
116 const int PAGE_COLUMNS = 10; ///< Number of Pages going across (columns)
117 const int PAGE_ROWS = 1; ///< Number of Pages going down (rows)
118 const int IMAGE_ROWS = 5; ///< Number of Images going down (rows) with a Page
120 const unsigned int IMAGE_THUMBNAIL_WIDTH = 256; ///< Width of Thumbnail Image in texels
121 const unsigned int IMAGE_THUMBNAIL_HEIGHT = 256; ///< Height of Thumbnail Image in texels
123 const float SPIN_DURATION = 1.0f; ///< Times to spin an Image by upon touching, each spin taking a second.
125 const float EFFECT_SNAP_DURATION(0.66f); ///< Scroll Snap Duration for Effects
126 const float EFFECT_FLICK_DURATION(0.5f); ///< Scroll Flick Duration for Effects
128 } // unnamed namespace
131 * This example shows how to do custom Scroll Effects
133 class ExampleController : public ConnectionTracker
139 * @param application class, stored as reference
141 ExampleController( Application& application )
142 : mApplication( application ),
145 mEffectMode(PageCarouselEffect)
147 // Connect to the Application's Init and orientation changed signal
148 mApplication.InitSignal().Connect(this, &ExampleController::OnInit);
153 // Nothing to do here; everything gets deleted automatically
157 * This method gets called once the main loop of application is up and running
159 void OnInit(Application& app)
161 Stage stage = Dali::Stage::GetCurrent();
162 stage.KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
164 // Hide the indicator bar
165 mApplication.GetWindow().ShowIndicator(Dali::Window::INVISIBLE);
167 // Creates a default view with a default tool bar.
168 // The view is added to the stage.
169 mContentLayer = DemoHelper::CreateView( app,
176 mEffectIcon[ PageCarouselEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE );
177 mEffectIconSelected[ PageCarouselEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE_SELECTED );
178 mEffectIcon[ PageCubeEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE );
179 mEffectIconSelected[ PageCubeEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE_SELECTED );
180 mEffectIcon[ PageSpiralEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE );
181 mEffectIconSelected[ PageSpiralEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE_SELECTED );
182 mEffectIcon[ PageWaveEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE );
183 mEffectIconSelected[ PageWaveEffect ] = ResourceImage::New( EFFECT_CAROUSEL_IMAGE_SELECTED );
185 // Create a effect change button. (right of toolbar)
186 mEffectChangeButton = Toolkit::PushButton::New();
187 mEffectChangeButton.ClickedSignal().Connect( this, &ExampleController::OnEffectTouched );
188 mToolBar.AddControl( mEffectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
190 // Create the content layer.
193 // Hack to force screen refresh.
194 Animation animation = Animation::New(1.0f);
195 animation.AnimateTo(Property(mContentLayer, Actor::Property::POSITION), Vector3::ZERO );
202 * Adds content to the ContentLayer. This is everything we see
203 * excluding the toolbar at the top.
205 void AddContentLayer()
207 Stage stage = Stage::GetCurrent();
208 Vector2 stageSize = stage.GetSize();
210 mScrollView = ScrollView::New();
211 mScrollView.SetAnchorPoint(AnchorPoint::CENTER);
212 mScrollView.SetParentOrigin(ParentOrigin::CENTER);
213 mContentLayer.Add( mScrollView );
214 mScrollView.SetSize( stageSize );
215 mScrollView.SetAxisAutoLock( true );
216 mScrollView.SetAxisAutoLockGradient( 1.0f );
218 mScrollView.ScrollStartedSignal().Connect( this, &ExampleController::OnScrollStarted );
219 mScrollView.ScrollCompletedSignal().Connect( this, &ExampleController::OnScrollCompleted );
221 for(int row = 0;row<PAGE_ROWS;row++)
223 for(int column = 0;column<PAGE_COLUMNS;column++)
225 Actor page = CreatePage();
227 page.SetPosition( column * stageSize.x, row * stageSize.y );
228 mScrollView.Add( page );
230 mPages.push_back(page);
238 * Updates the ScrollView and it's children based
239 * on the current effect.
243 std::stringstream ss(APPLICATION_TITLE);
244 ss << APPLICATION_TITLE << ": " << EFFECT_MODE_NAME[mEffectMode];
247 mEffectChangeButton.SetButtonImage( mEffectIcon[ mEffectMode ] );
248 mEffectChangeButton.SetSelectedImage( mEffectIconSelected[ mEffectMode ] );
250 // remove old Effect if exists.
251 if(mScrollViewEffect)
253 mScrollView.RemoveEffect(mScrollViewEffect);
256 // apply new Effect to ScrollView
257 ApplyEffectToScrollView();
258 unsigned int pageCount(0);
259 for( std::vector< Actor >::iterator pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter)
261 Actor page = *pageIter;
262 ApplyEffectToPage( page, pageCount++ );
267 * Creates a page using a source of images.
271 Actor page = Actor::New();
272 page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
273 page.SetParentOrigin( ParentOrigin::CENTER );
274 page.SetAnchorPoint( AnchorPoint::CENTER );
276 Stage stage = Stage::GetCurrent();
277 Vector2 stageSize = stage.GetSize();
279 const float margin = 10.0f;
281 // Calculate the number of images going across (columns) within a page, according to the screen resolution and dpi.
282 int imageColumns = round(IMAGE_ROWS * (stageSize.x / stage.GetDpi().x) / (stageSize.y / stage.GetDpi().y));
283 const Vector3 imageSize((stageSize.x / imageColumns) - margin, (stageSize.y / IMAGE_ROWS) - margin, 0.0f);
285 for(int row = 0;row<IMAGE_ROWS;row++)
287 for(int column = 0;column<imageColumns;column++)
289 ImageActor image = CreateImage( GetNextImagePath(), imageSize.x, imageSize.y );
291 image.SetParentOrigin( ParentOrigin::CENTER );
292 image.SetAnchorPoint( AnchorPoint::CENTER );
294 Vector3 position( margin * 0.5f + (imageSize.x + margin) * column - stageSize.width * 0.5f,
295 margin * 0.5f + (imageSize.y + margin) * row - stageSize.height * 0.5f,
297 image.SetPosition( position + imageSize * 0.5f );
298 image.SetSize( imageSize );
308 * Applies effect to scrollView
310 void ApplyEffectToScrollView()
315 Stage stage = Stage::GetCurrent();
316 Vector2 stageSize = stage.GetSize();
318 RulerPtr rulerX = CreateRuler(snap ? stageSize.width : 0.0f);
319 RulerPtr rulerY = new DefaultRuler;
320 rulerX->SetDomain(RulerDomain(0.0f, stageSize.x * PAGE_COLUMNS, !wrap));
323 Dali::Path path = Dali::Path::New();
324 Dali::Property::Array points;
326 Dali::Property::Array controlPoints;
327 controlPoints.Resize(4);
329 if( mEffectMode == PageCarouselEffect)
332 points[0] = Vector3( stageSize.x*0.75, 0.0f, -stageSize.x*0.75f);
333 points[1] = Vector3( 0.0f, 0.0f, 0.0f );
334 points[2] = Vector3( -stageSize.x*0.75f, 0.0f, -stageSize.x*0.75f);
335 path.SetProperty( Path::Property::POINTS, points );
337 controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, 0.0f );
338 controlPoints[1] = Vector3( stageSize.x*0.5f, 0.0f, 0.0f );
339 controlPoints[2] = Vector3(-stageSize.x*0.5f, 0.0f, 0.0f );
340 controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f, 0.0f );
341 path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
343 forward = Vector3::ZERO;
345 else if( mEffectMode == PageCubeEffect)
347 points[0] = Vector3( stageSize.x*0.5, 0.0f, stageSize.x*0.5f);
348 points[1] = Vector3( 0.0f, 0.0f, 0.0f );
349 points[2] = Vector3( -stageSize.x*0.5f, 0.0f, stageSize.x*0.5f);
350 path.SetProperty( Path::Property::POINTS, points );
352 controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, stageSize.x*0.3f );
353 controlPoints[1] = Vector3( stageSize.x*0.3f, 0.0f, 0.0f );
354 controlPoints[2] = Vector3(-stageSize.x*0.3f, 0.0f, 0.0f );
355 controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f, stageSize.x*0.3f );
356 path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
358 forward = Vector3(-1.0f,0.0f,0.0f);
360 else if( mEffectMode == PageSpiralEffect)
362 points[0] = Vector3( stageSize.x*0.5, 0.0f, -stageSize.x*0.5f);
363 points[1] = Vector3( 0.0f, 0.0f, 0.0f );
364 points[2] = Vector3( -stageSize.x*0.5f, 0.0f, -stageSize.x*0.5f);
365 path.SetProperty( Path::Property::POINTS, points );
367 controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, 0.0f );
368 controlPoints[1] = Vector3( stageSize.x*0.5f, 0.0f, 0.0f );
369 controlPoints[2] = Vector3(-stageSize.x*0.5f, 0.0f, 0.0f );
370 controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f, 0.0f );
371 path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
373 forward = Vector3(-1.0f,0.0f,0.0f);
375 else if( mEffectMode == PageWaveEffect)
377 points[0] = Vector3( stageSize.x, 0.0f, -stageSize.x);
378 points[1] = Vector3( 0.0f, 0.0f, 0.0f );
379 points[2] = Vector3( -stageSize.x, 0.0f, -stageSize.x);
380 path.SetProperty( Path::Property::POINTS, points );
382 controlPoints[0] = Vector3( 0.0f, 0.0f, -stageSize.x );
383 controlPoints[1] = Vector3( stageSize.x*0.5f, 0.0f, 0.0f );
384 controlPoints[2] = Vector3( -stageSize.x*0.5f, 0.0f, 0.0f);
385 controlPoints[3] = Vector3(0.0f, 0.0f,-stageSize.x );
386 path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
388 forward = Vector3(-1.0f,0.0f,0.0f);
391 mScrollViewEffect = ScrollViewPagePathEffect::New(path, forward,Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(stageSize.x,stageSize.y,0.0f),PAGE_COLUMNS);
392 mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
393 mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
394 mScrollView.SetScrollSnapAlphaFunction(AlphaFunction::EASE_OUT);
395 mScrollView.SetScrollFlickAlphaFunction(AlphaFunction::EASE_OUT);
396 mScrollView.RemoveConstraintsFromChildren();
398 rulerX = CreateRuler(snap ? stageSize.width * 0.5f : 0.0f);
401 rulerX->SetDomain(RulerDomain(0.0f, stageSize.x * 0.5f * PAGE_COLUMNS, !wrap));
405 rulerX->SetDomain(RulerDomain(0.0f, stageSize.x*0.5f* (PAGE_COLUMNS+1), !wrap));
408 unsigned int currentPage = mScrollView.GetCurrentPage();
409 if( mScrollViewEffect )
411 mScrollView.ApplyEffect(mScrollViewEffect);
414 mScrollView.SetWrapMode(wrap);
415 mScrollView.SetRulerX( rulerX );
416 mScrollView.SetRulerY( rulerY );
418 mScrollView.ScrollTo( currentPage, 0.0f );
422 * Creates a Ruler that snaps to a specified grid size.
423 * If that grid size is 0.0 then this ruler does not
426 * @param[in] gridSize (optional) The grid size for the ruler,
427 * (Default = 0.0 i.e. no snapping)
428 * @return The ruler is returned.
430 RulerPtr CreateRuler(float gridSize = 0.0f)
432 if(gridSize <= Math::MACHINE_EPSILON_0)
434 return new DefaultRuler();
436 return new FixedRuler(gridSize);
441 * Applies effect to the pages within scroll view.
443 * @param[in] page The page Actor to apply effect to.
445 void ApplyEffectToPage(Actor page, unsigned int pageOrder )
447 page.RemoveConstraints();
448 page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
450 ScrollViewPagePathEffect effect = ScrollViewPagePathEffect::DownCast( mScrollViewEffect );
451 effect.ApplyToPage( page, pageOrder );
455 * Creates an Image (Helper)
457 * @param[in] filename the path of the image.
458 * @param[in] width the width of the image in texels
459 * @param[in] height the height of the image in texels.
461 ImageActor CreateImage( const std::string& filename, unsigned int width = IMAGE_THUMBNAIL_WIDTH, unsigned int height = IMAGE_THUMBNAIL_HEIGHT )
463 Image img = ResourceImage::New(filename, ImageDimensions( width, height ), Dali::FittingMode::SCALE_TO_FILL, Dali::SamplingMode::BOX_THEN_LINEAR );
465 ImageActor actor = ImageActor::New(img);
466 actor.SetName( filename );
467 actor.SetParentOrigin(ParentOrigin::CENTER);
468 actor.SetAnchorPoint(AnchorPoint::CENTER);
470 actor.TouchedSignal().Connect( this, &ExampleController::OnTouchImage );
475 * When scroll starts (i.e. user starts to drag scrollview),
476 * note this state (mScrolling = true)
477 * @param[in] position Current Scroll Position
479 void OnScrollStarted( const Vector2& position )
485 * When scroll starts (i.e. user stops dragging scrollview, and scrollview has snapped to destination),
486 * note this state (mScrolling = false)
487 * @param[in] position Current Scroll Position
489 void OnScrollCompleted( const Vector2& position )
495 * Upon Touching an image (Release), make it spin
496 * (provided we're not scrolling).
497 * @param[in] actor The actor touched
498 * @param[in] event The TouchEvent.
500 bool OnTouchImage( Actor actor, const TouchEvent& event )
502 if( (event.points.size() > 0) && (!mScrolling) )
504 TouchPoint point = event.points[0];
505 if(point.state == TouchPoint::Up)
507 // Spin the Image a few times.
508 Animation animation = Animation::New(SPIN_DURATION);
509 animation.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f * SPIN_DURATION) ), Vector3::XAXIS ), AlphaFunction::EASE_OUT );
517 * Signal handler, called when the 'Effect' button has been touched.
519 * @param[in] button The button that was pressed.
521 bool OnEffectTouched(Button button)
523 mEffectMode = static_cast<EffectMode>((static_cast<int>(mEffectMode) + 1) % static_cast<int>(Total));
529 * Sets/Updates the title of the View
530 * @param[in] title The new title for the view.
532 void SetTitle(const std::string& title)
536 mTitleActor = DemoHelper::CreateToolBarLabel( "" );
537 // Add title to the tool bar.
538 mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
541 mTitleActor.SetProperty( Toolkit::TextLabel::Property::TEXT, title );
545 * Main key event handler
547 void OnKeyEvent(const KeyEvent& event)
549 if(event.state == KeyEvent::Down)
551 if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
560 Application& mApplication; ///< Application instance
561 Toolkit::Control mView; ///< The View instance.
562 Toolkit::ToolBar mToolBar; ///< The View's Toolbar.
563 TextLabel mTitleActor; ///< The Toolbar's Title.
564 Layer mContentLayer; ///< The content layer (contains game actors)
565 ScrollView mScrollView; ///< ScrollView UI Component
566 bool mScrolling; ///< ScrollView scrolling state (true = scrolling, false = stationary)
567 ScrollViewEffect mScrollViewEffect; ///< ScrollView Effect instance.
568 std::vector< Actor > mPages; ///< Keeps track of all the pages for applying effects.
571 * Enumeration of different effects this scrollview can operate under.
575 PageCarouselEffect, ///< Page carousel effect
576 PageCubeEffect, ///< Page cube effect
577 PageSpiralEffect, ///< Page spiral effect
578 PageWaveEffect, ///< Page wave effect
583 EffectMode mEffectMode; ///< Current Effect mode
585 Image mEffectIcon[Total]; ///< Icons for the effect button
586 Image mEffectIconSelected[Total]; ///< Icons for the effect button when its selected
587 Toolkit::PushButton mEffectChangeButton; ///< Effect Change Button
590 int main(int argc, char **argv)
592 Application app = Application::New(&argc, &argv, DALI_DEMO_THEME_PATH);
593 ExampleController test(app);