2 * Copyright (c) 2019 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.
19 * @file image-scaling-irregular-grid-example.cpp
20 * @brief Demonstrates how to use image scaling modes when loading images.
22 * If an image is going to be drawn on-screen at a lower resolution than it is
23 * stored at on-disk, the scaling feature of the image loader can be used to
24 * reduce the image to save memory, improve performance, and potentially display
25 * a better small version of the image than if the default size were loaded.
27 * The functions CreateImage and CreateImageView below show how to build an
28 * image using a scaling mode to have %Dali resize it during loading.
30 * This demo defaults to the SCALE_TO_FILL mode of ImageAttributes which makes
31 * sure that every pixel in the loaded image is filled with a source colour
32 * from the image's central region while losing the minimum number of pixels
34 * It is the best option for producing thumbnails of input images that have
35 * diverse aspect ratios.
37 * The other four scaling modes of dali can be cycled-through for the whole
38 * grid using the button in the top-right of the toolbar.
39 * A single image can be cycled by clicking the image directly.
41 * @see CreateImage CreateImageView
47 #include <dali-toolkit/dali-toolkit.h>
49 #include <dali-toolkit/devel-api/controls/control-devel.h>
50 #include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
53 #include "grid-flags.h"
54 #include "shared/view.h"
57 using namespace Dali::Toolkit;
58 using namespace Dali::Demo;
63 /** Controls the output of application logging. */
64 //#define DEBUG_PRINT_DIAGNOSTICS;
66 const char* BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-gradient.jpg" );
67 const char* TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
68 const char* APPLICATION_TITLE( "Image Scaling Modes" );
69 const char* TOGGLE_SCALING_IMAGE( DEMO_IMAGE_DIR "icon-change.png" );
70 const char* TOGGLE_SCALING_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-change-selected.png" );
72 /** The width of the grid in whole grid cells. */
73 const unsigned GRID_WIDTH = 9;
74 /** Limit the grid to be no higher than this in units of a cell. */
75 const unsigned GRID_MAX_HEIGHT = 600;
77 /** The space between the edge of a grid cell and the image embedded within it. */
78 const unsigned GRID_CELL_PADDING = 4;
80 /** The aspect ratio of cells in the image grid. */
81 const float CELL_ASPECT_RATIO = 1.33333333333333333333f;
83 const Dali::FittingMode::Type DEFAULT_SCALING_MODE = Dali::FittingMode::SCALE_TO_FILL;
85 /** The number of times to spin an image on touching, each spin taking a second.*/
86 const float SPIN_DURATION = 1.0f;
88 /** The target image sizes in grid cells. */
89 const Vector2 IMAGE_SIZES[] = {
97 // Large, tall configuration:
98 Vector2( GRID_WIDTH / 2, GRID_WIDTH + GRID_WIDTH / 2 ),
99 // Large, square-ish images to show shrink-to-fit well with wide and tall images:
100 Vector2( GRID_WIDTH / 2, GRID_WIDTH / 2.0f * CELL_ASPECT_RATIO + 0.5f ),
101 Vector2( GRID_WIDTH - 2, (GRID_WIDTH - 2) * CELL_ASPECT_RATIO + 0.5f ),
103 const unsigned NUM_IMAGE_SIZES = sizeof(IMAGE_SIZES) / sizeof(IMAGE_SIZES[0]);
105 /** Images to load into the grid. These are mostly large and non-square to
106 * show the scaling. */
107 const char* IMAGE_PATHS[] = {
109 DEMO_IMAGE_DIR "dali-logo.png",
110 DEMO_IMAGE_DIR "com.samsung.dali-demo.ico",
111 DEMO_IMAGE_DIR "square_primitive_shapes.bmp",
112 DEMO_IMAGE_DIR "gallery-large-14.wbmp",
114 // Images that show aspect ratio changes clearly in primitive shapes:
116 DEMO_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
117 DEMO_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
119 // Images from other demos that are tall, wide or just large:
121 DEMO_IMAGE_DIR "gallery-large-1.jpg",
122 DEMO_IMAGE_DIR "gallery-large-2.jpg",
123 DEMO_IMAGE_DIR "gallery-large-3.jpg",
124 DEMO_IMAGE_DIR "gallery-large-4.jpg",
125 DEMO_IMAGE_DIR "gallery-large-5.jpg",
126 DEMO_IMAGE_DIR "gallery-large-6.jpg",
127 DEMO_IMAGE_DIR "gallery-large-7.jpg",
128 DEMO_IMAGE_DIR "gallery-large-8.jpg",
129 DEMO_IMAGE_DIR "gallery-large-9.jpg",
130 DEMO_IMAGE_DIR "gallery-large-10.jpg",
131 DEMO_IMAGE_DIR "gallery-large-11.jpg",
132 DEMO_IMAGE_DIR "gallery-large-12.jpg",
133 DEMO_IMAGE_DIR "gallery-large-13.jpg",
134 DEMO_IMAGE_DIR "gallery-large-14.jpg",
135 DEMO_IMAGE_DIR "gallery-large-15.jpg",
136 DEMO_IMAGE_DIR "gallery-large-16.jpg",
137 DEMO_IMAGE_DIR "gallery-large-17.jpg",
138 DEMO_IMAGE_DIR "gallery-large-18.jpg",
139 DEMO_IMAGE_DIR "gallery-large-19.jpg",
140 DEMO_IMAGE_DIR "gallery-large-20.jpg",
141 DEMO_IMAGE_DIR "gallery-large-21.jpg",
143 DEMO_IMAGE_DIR "background-1.jpg",
144 DEMO_IMAGE_DIR "background-2.jpg",
145 DEMO_IMAGE_DIR "background-3.jpg",
146 DEMO_IMAGE_DIR "background-4.jpg",
147 DEMO_IMAGE_DIR "background-5.jpg",
148 DEMO_IMAGE_DIR "background-blocks.jpg",
149 DEMO_IMAGE_DIR "background-magnifier.jpg",
151 DEMO_IMAGE_DIR "background-1.jpg",
152 DEMO_IMAGE_DIR "background-2.jpg",
153 DEMO_IMAGE_DIR "background-3.jpg",
154 DEMO_IMAGE_DIR "background-4.jpg",
155 DEMO_IMAGE_DIR "background-5.jpg",
156 DEMO_IMAGE_DIR "background-blocks.jpg",
157 DEMO_IMAGE_DIR "background-magnifier.jpg",
159 DEMO_IMAGE_DIR "book-landscape-cover-back.jpg",
160 DEMO_IMAGE_DIR "book-landscape-cover.jpg",
161 DEMO_IMAGE_DIR "book-landscape-p1.jpg",
162 DEMO_IMAGE_DIR "book-landscape-p2.jpg",
164 DEMO_IMAGE_DIR "book-portrait-cover.jpg",
165 DEMO_IMAGE_DIR "book-portrait-p1.jpg",
166 DEMO_IMAGE_DIR "book-portrait-p2.jpg",
169 const unsigned NUM_IMAGE_PATHS = sizeof(IMAGE_PATHS) / sizeof(IMAGE_PATHS[0]) - 1u;
170 const unsigned int INITIAL_IMAGES_TO_LOAD = 10;
174 * Creates an ImageView
176 * @param[in] filename The path of the image.
177 * @param[in] width The width of the image in pixels.
178 * @param[in] height The height of the image in pixels.
179 * @param[in] fittingMode The mode to use when scaling the image to fit the desired dimensions.
181 ImageView CreateImageView(const std::string& filename, int width, int height, Dali::FittingMode::Type fittingMode )
184 ImageView imageView = ImageView::New();
187 map[Toolkit::ImageVisual::Property::URL] = filename;
188 map[Toolkit::ImageVisual::Property::DESIRED_WIDTH] = width;
189 map[Toolkit::ImageVisual::Property::DESIRED_HEIGHT] = height;
190 map[Toolkit::ImageVisual::Property::FITTING_MODE] = fittingMode;
191 imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
193 imageView.SetProperty( Dali::Actor::Property::NAME, filename );
194 imageView.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
195 imageView.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::CENTER);
200 /** Cycle the scaling mode options. */
201 Dali::FittingMode::Type NextMode( const Dali::FittingMode::Type oldMode )
203 Dali::FittingMode::Type newMode = FittingMode::SHRINK_TO_FIT;
206 case FittingMode::SHRINK_TO_FIT:
207 newMode = FittingMode::SCALE_TO_FILL;
209 case FittingMode::SCALE_TO_FILL:
210 newMode = FittingMode::FIT_WIDTH;
212 case FittingMode::FIT_WIDTH:
213 newMode = FittingMode::FIT_HEIGHT;
215 case FittingMode::FIT_HEIGHT:
216 newMode = FittingMode::SHRINK_TO_FIT;
223 * Bundle an image path with the rectangle to pack it into.
225 struct ImageConfiguration
227 ImageConfiguration( const char * const path, const Vector2 dimensions ) :
229 dimensions( dimensions )
236 * Post-layout image data.
238 struct PositionedImage
240 PositionedImage(ImageConfiguration& configuration, unsigned cellX, unsigned cellY, Vector2 imageGridDims) :
241 configuration( configuration ),
244 imageGridDims( imageGridDims )
247 ImageConfiguration configuration;
250 Vector2 imageGridDims;
256 * @brief The main class of the demo.
258 class ImageScalingIrregularGridController : public ConnectionTracker
262 ImageScalingIrregularGridController( Application& application )
263 : mApplication( application ),
267 std::cout << "ImageScalingIrregularGridController::ImageScalingIrregularGridController" << std::endl;
269 // Connect to the Application's Init signal
270 mApplication.InitSignal().Connect( this, &ImageScalingIrregularGridController::Create );
273 ~ImageScalingIrregularGridController()
275 // Nothing to do here.
279 * Called everytime an ImageView has loaded it's image
281 void ResourceReadySignal( Toolkit::Control control )
284 // To allow fast startup, we only place a small number of ImageViews on stage first
285 if ( mImagesLoaded == INITIAL_IMAGES_TO_LOAD )
287 // Adding the ImageViews to the stage will trigger loading of the Images
288 mGridActor.Add( mOffStageImageViews );
294 * One-time setup in response to Application InitSignal.
296 void Create( Application& application )
298 std::cout << "ImageScalingIrregularGridController::Create" << std::endl;
300 // Get a handle to the stage:
301 Stage stage = Stage::GetCurrent();
303 // Connect to input event signals:
304 stage.KeyEventSignal().Connect(this, &ImageScalingIrregularGridController::OnKeyEvent);
306 // Hide the indicator bar
307 mApplication.GetWindow().ShowIndicator(Dali::Window::INVISIBLE);
309 // Create a default view with a default tool bar:
310 mContentLayer = DemoHelper::CreateView( mApplication,
317 // Create an image scaling toggle button. (right of toolbar)
318 Toolkit::PushButton toggleScalingButton = Toolkit::PushButton::New();
319 toggleScalingButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, TOGGLE_SCALING_IMAGE );
320 toggleScalingButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, TOGGLE_SCALING_IMAGE_SELECTED );
321 toggleScalingButton.ClickedSignal().Connect( this, &ImageScalingIrregularGridController::OnToggleScalingTouched );
322 mToolBar.AddControl( toggleScalingButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
324 SetTitle( APPLICATION_TITLE );
326 mOffStageImageViews = Actor::New();
327 mOffStageImageViews.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
328 mOffStageImageViews.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
329 mOffStageImageViews.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
331 // Build the main content of the widow:
332 PopulateContentLayer( DEFAULT_SCALING_MODE );
336 * Build the main part of the application's view.
338 void PopulateContentLayer( const Dali::FittingMode::Type fittingMode )
340 Stage stage = Stage::GetCurrent();
341 Vector2 stageSize = stage.GetSize();
344 Actor imageField = BuildImageField( stageSize.x, GRID_WIDTH, GRID_MAX_HEIGHT, fittingMode, fieldHeight );
346 mScrollView = ScrollView::New();
348 mScrollView.ScrollStartedSignal().Connect( this, &ImageScalingIrregularGridController::OnScrollStarted );
349 mScrollView.ScrollCompletedSignal().Connect( this, &ImageScalingIrregularGridController::OnScrollCompleted );
351 mScrollView.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::CENTER);
352 mScrollView.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
354 mScrollView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
356 mScrollView.SetAxisAutoLock( true );
357 mScrollView.SetAxisAutoLockGradient( 1.0f );
359 // Restrict scrolling to mostly vertical only, but with some horizontal wiggle-room:
361 RulerPtr rulerX = new FixedRuler( stageSize.width ); //< Pull the view back to the grid's centre-line when touch is release using a snapping ruler.
362 rulerX->SetDomain( RulerDomain( stageSize.width * -0.125f, stageSize.width * 1.125f ) ); //< Scroll slightly left/right of image field.
363 mScrollView.SetRulerX ( rulerX );
365 RulerPtr rulerY = new DefaultRuler(); //< Snap in multiples of a screen / stage height
366 rulerY->SetDomain( RulerDomain( - fieldHeight * 0.5f + stageSize.height * 0.5f - GRID_CELL_PADDING, fieldHeight * 0.5f + stageSize.height * 0.5f + GRID_CELL_PADDING ) );
367 mScrollView.SetRulerY ( rulerY );
369 mContentLayer.Add( mScrollView );
370 mScrollView.Add( imageField );
371 mGridActor = imageField;
373 // Create the scroll bar
374 mScrollBarVertical = ScrollBar::New(Toolkit::ScrollBar::Vertical);
375 mScrollBarVertical.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::TOP_RIGHT);
376 mScrollBarVertical.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_RIGHT);
377 mScrollBarVertical.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::HEIGHT);
378 mScrollBarVertical.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
379 mScrollView.Add(mScrollBarVertical);
381 mScrollBarHorizontal = ScrollBar::New(Toolkit::ScrollBar::Horizontal);
382 mScrollBarHorizontal.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::BOTTOM_LEFT);
383 mScrollBarHorizontal.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT);
384 mScrollBarHorizontal.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
385 mScrollBarHorizontal.SetProperty( Actor::Property::ORIENTATION, Quaternion( Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS) ) );
386 mScrollView.Add(mScrollBarHorizontal);
388 mScrollView.OnRelayoutSignal().Connect( this, &ImageScalingIrregularGridController::OnScrollViewRelayout );
390 // Scroll to top of grid so first images loaded are on-screen:
391 mScrollView.ScrollTo( Vector2( 0, -1000000 ) );
394 void OnScrollViewRelayout(Actor actor)
396 // Make the height of the horizontal scroll bar to be the same as the width of scroll view.
397 mScrollBarHorizontal.SetProperty( Actor::Property::SIZE, Vector2(0.0f, mScrollView.GetRelayoutSize( Dimension::WIDTH) ));
401 * Build a field of images scaled into a variety of shapes from very wide,
402 * through square, to very tall. The images are direct children of the Dali::Actor
405 Actor BuildImageField( const float fieldWidth,
406 const unsigned gridWidth,
407 const unsigned maxGridHeight,
408 Dali::FittingMode::Type fittingMode,
409 float & outFieldHeight )
411 // Generate the list of image configurations to be fitted into the field:
413 std::vector<ImageConfiguration> configurations;
414 configurations.reserve( NUM_IMAGE_PATHS * NUM_IMAGE_SIZES );
415 for( unsigned imageIndex = 0; imageIndex < NUM_IMAGE_PATHS; ++imageIndex )
417 for( unsigned dimensionsIndex = 0; dimensionsIndex < NUM_IMAGE_SIZES; ++ dimensionsIndex )
419 configurations.push_back( ImageConfiguration( IMAGE_PATHS[imageIndex], IMAGE_SIZES[dimensionsIndex] ) );
422 // Stir-up the list to get some nice irregularity in the generated field:
423 std::random_shuffle( configurations.begin(), configurations.end() );
424 std::random_shuffle( configurations.begin(), configurations.end() );
426 // Place the images in the grid:
428 std::vector<ImageConfiguration>::iterator config, end;
429 GridFlags grid( gridWidth, maxGridHeight );
430 std::vector<PositionedImage> placedImages;
432 for( config = configurations.begin(), end = configurations.end(); config != end; ++config )
434 unsigned cellX, cellY;
435 Vector2 imageGridDims;
437 // Allocate a region of the grid for the image:
438 bool allocated = grid.AllocateRegion( config->dimensions, cellX, cellY, imageGridDims );
441 #ifdef DEBUG_PRINT_DIAGNOSTICS
442 fprintf( stderr, "Failed to allocate image in grid with dims (%f, %f) and path: %s.\n", config->dimensions.x, config->dimensions.y, config->path );
447 placedImages.push_back( PositionedImage( *config, cellX, cellY, imageGridDims ) );
449 DALI_ASSERT_DEBUG( grid.DebugCheckGridValid() && "Cells were set more than once, indicating erroneous overlap in placing images on the grid." );
450 const unsigned actualGridHeight = grid.GetHighestUsedRow() + 1;
452 // Take the images images in the grid and turn their logical locations into
453 // coordinates in a frame defined by a parent actor:
455 Actor gridActor = Actor::New();
456 gridActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
457 gridActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
458 gridActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
460 // Work out the constants of the grid and cell dimensions and positions:
461 const float cellWidth = fieldWidth / gridWidth;
462 const float cellHeight = cellWidth / CELL_ASPECT_RATIO;
463 const Vector2 cellSize = Vector2( cellWidth, cellHeight );
464 outFieldHeight = actualGridHeight * cellHeight;
465 const Vector2 gridOrigin = Vector2( -fieldWidth * 0.5f, -outFieldHeight * 0.5 );
467 unsigned int count = 0;
468 // Build the image actors in their right locations in their parent's frame:
469 for( std::vector<PositionedImage>::const_iterator i = placedImages.begin(), end = placedImages.end(); i != end; ++i, ++count )
471 const PositionedImage& imageSource = *i;
472 const Vector2 imageSize = imageSource.imageGridDims * cellSize - Vector2( GRID_CELL_PADDING * 2, GRID_CELL_PADDING * 2 );
473 const Vector2 imageRegionCorner = gridOrigin + cellSize * Vector2( imageSource.cellX, imageSource.cellY );
474 const Vector2 imagePosition = imageRegionCorner + Vector2( GRID_CELL_PADDING , GRID_CELL_PADDING ) + imageSize * 0.5f;
476 ImageView image = CreateImageView( imageSource.configuration.path, imageSize.x, imageSize.y, fittingMode );
477 image.SetProperty( Actor::Property::POSITION, Vector3( imagePosition.x, imagePosition.y, 0 ) );
478 image.SetProperty( Actor::Property::SIZE, imageSize );
479 image.TouchSignal().Connect( this, &ImageScalingIrregularGridController::OnTouchImage );
480 image.ResourceReadySignal().Connect( this, &ImageScalingIrregularGridController::ResourceReadySignal );
481 mFittingModes[image.GetProperty< int >( Actor::Property::ID )] = fittingMode;
482 mResourceUrls[image.GetProperty< int >( Actor::Property::ID )] = imageSource.configuration.path;
483 mSizes[image.GetProperty< int >( Actor::Property::ID )] = imageSize;
484 if ( count < INITIAL_IMAGES_TO_LOAD )
486 gridActor.Add( image );
490 // Store the ImageView in an offstage actor until the inital batch of ImageViews have finished loading their images
492 mOffStageImageViews.Add( image );
500 * Upon Touching an image (Release), change its scaling mode and make it spin, provided we're not scrolling.
501 * @param[in] actor The actor touched
502 * @param[in] event The Touch information.
504 bool OnTouchImage( Actor actor, const TouchData& event )
506 if( ( event.GetPointCount() > 0 ) && ( !mScrolling ) )
508 if( event.GetState( 0 ) == PointState::UP )
510 // Spin the image a few times:
511 Animation animation = Animation::New(SPIN_DURATION);
512 animation.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f * SPIN_DURATION) ), Vector3::XAXIS ), AlphaFunction::EASE_OUT );
515 // Change the scaling mode:
516 const unsigned id = actor.GetProperty< int >( Actor::Property::ID );
517 Dali::FittingMode::Type newMode = NextMode( mFittingModes[id] );
518 const Vector2 imageSize = mSizes[actor.GetProperty< int >( Actor::Property::ID )];
520 ImageView imageView = ImageView::DownCast( actor );
524 map[Visual::Property::TYPE] = Visual::IMAGE;
525 map[ImageVisual::Property::URL] = mResourceUrls[id];
526 map[ImageVisual::Property::DESIRED_WIDTH] = imageSize.width + 0.5f;
527 map[ImageVisual::Property::DESIRED_HEIGHT] = imageSize.height + 0.5f;
528 map[ImageVisual::Property::FITTING_MODE] = newMode;
529 imageView.SetProperty( ImageView::Property::IMAGE, map );
532 mFittingModes[id] = newMode;
539 * Main key event handler.
540 * Quit on escape key.
542 void OnKeyEvent(const KeyEvent& event)
544 if( event.state == KeyEvent::Down )
546 if( IsKey( event, Dali::DALI_KEY_ESCAPE )
547 || IsKey( event, Dali::DALI_KEY_BACK ) )
555 * Signal handler, called when the 'Scaling' button has been touched.
557 * @param[in] button The button that was pressed.
559 bool OnToggleScalingTouched( Button button )
561 const unsigned numChildren = mGridActor.GetChildCount();
563 for( unsigned i = 0; i < numChildren; ++i )
565 ImageView gridImageView = ImageView::DownCast( mGridActor.GetChildAt( i ) );
568 // Cycle the scaling mode options:
569 unsigned int id = gridImageView.GetProperty< int >( Actor::Property::ID );
571 const Vector2 imageSize = mSizes[ id ];
572 Dali::FittingMode::Type newMode = NextMode( mFittingModes[ id ] );
575 map[Visual::Property::TYPE] = Visual::IMAGE;
576 map[ImageVisual::Property::URL] = mResourceUrls[id];
577 map[ImageVisual::Property::DESIRED_WIDTH] = imageSize.width;
578 map[ImageVisual::Property::DESIRED_HEIGHT] = imageSize.height;
579 map[ImageVisual::Property::FITTING_MODE] = newMode;
580 gridImageView.SetProperty( ImageView::Property::IMAGE, map );
584 mFittingModes[ id ] = newMode;
586 SetTitle( std::string( newMode == FittingMode::SHRINK_TO_FIT ? "SHRINK_TO_FIT" : newMode == FittingMode::SCALE_TO_FILL ? "SCALE_TO_FILL" : newMode == FittingMode::FIT_WIDTH ? "FIT_WIDTH" : "FIT_HEIGHT" ) );
593 * Sets/Updates the title of the View
594 * @param[in] title The new title for the view.
596 void SetTitle(const std::string& title)
600 mTitleActor = DemoHelper::CreateToolBarLabel( "" );
601 // Add title to the tool bar.
602 mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
605 mTitleActor.SetProperty( TextLabel::Property::TEXT, title );
609 * When scroll starts (i.e. user starts to drag scrollview),
610 * note this state (mScrolling = true)
611 * @param[in] position Current Scroll Position
613 void OnScrollStarted( const Vector2& position )
619 * When scroll starts (i.e. user stops dragging scrollview, and scrollview has snapped to destination),
620 * note this state (mScrolling = false).
621 * @param[in] position Current Scroll Position
623 void OnScrollCompleted( const Vector2& position )
629 Application& mApplication;
631 Layer mContentLayer; ///< The content layer (contains non gui chrome actors)
632 Toolkit::Control mView; ///< The View instance.
633 Toolkit::ToolBar mToolBar; ///< The View's Toolbar.
634 TextLabel mTitleActor; ///< The Toolbar's Title.
635 Actor mGridActor; ///< The container for the grid of images
636 Actor mOffStageImageViews; ///< ImageViews held off stage until the inital batch have loaded their images
637 ScrollView mScrollView; ///< ScrollView UI Component
638 ScrollBar mScrollBarVertical;
639 ScrollBar mScrollBarHorizontal;
640 bool mScrolling; ///< ScrollView scrolling state (true = scrolling, false = stationary)
641 std::map<unsigned, Dali::FittingMode::Type> mFittingModes; ///< Stores the current scaling mode of each image, keyed by image actor id.
642 std::map<unsigned, std::string> mResourceUrls; ///< Stores the url of each image, keyed by image actor id.
643 std::map<unsigned, Vector2> mSizes; ///< Stores the current size of each image, keyed by image actor id.
644 unsigned int mImagesLoaded; ///< How many images have been loaded
647 int DALI_EXPORT_API main( int argc, char **argv )
649 Application application = Application::New( &argc, &argv, DEMO_THEME_PATH );
650 ImageScalingIrregularGridController test( application );
651 application.MainLoop();