2 * Copyright (c) 2021 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
45 #include <dali-toolkit/dali-toolkit.h>
46 #include <dali-toolkit/devel-api/controls/control-devel.h>
47 #include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
49 #include <chrono> // std::chrono::system_clock
52 #include <random> // std::default_random_engine
55 #include "grid-flags.h"
56 #include "shared/view.h"
59 using namespace Dali::Toolkit;
60 using namespace Dali::Demo;
64 /** Controls the output of application logging. */
65 //#define DEBUG_PRINT_DIAGNOSTICS;
67 const char* BACKGROUND_IMAGE(DEMO_IMAGE_DIR "background-gradient.jpg");
68 const char* TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
69 const char* APPLICATION_TITLE("Image Scaling Modes");
70 const char* TOGGLE_SCALING_IMAGE(DEMO_IMAGE_DIR "icon-change.png");
71 const char* TOGGLE_SCALING_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-change-selected.png");
73 /** The width of the grid in whole grid cells. */
74 const unsigned GRID_WIDTH = 9;
75 /** Limit the grid to be no higher than this in units of a cell. */
76 const unsigned GRID_MAX_HEIGHT = 600;
78 /** The space between the edge of a grid cell and the image embedded within it. */
79 const unsigned GRID_CELL_PADDING = 4;
81 /** The aspect ratio of cells in the image grid. */
82 const float CELL_ASPECT_RATIO = 1.33333333333333333333f;
84 const Dali::FittingMode::Type DEFAULT_SCALING_MODE = Dali::FittingMode::SCALE_TO_FILL;
86 /** The number of times to spin an image on touching, each spin taking a second.*/
87 const float SPIN_DURATION = 1.0f;
89 /** The target image sizes in grid cells. */
90 const Vector2 IMAGE_SIZES[] = {
98 // Large, tall configuration:
99 Vector2(GRID_WIDTH / 2, GRID_WIDTH + GRID_WIDTH / 2),
100 // Large, square-ish images to show shrink-to-fit well with wide and tall images:
101 Vector2(GRID_WIDTH / 2, GRID_WIDTH / 2.0f * CELL_ASPECT_RATIO + 0.5f),
102 Vector2(GRID_WIDTH - 2, (GRID_WIDTH - 2) * CELL_ASPECT_RATIO + 0.5f),
104 const unsigned NUM_IMAGE_SIZES = sizeof(IMAGE_SIZES) / sizeof(IMAGE_SIZES[0]);
106 /** Images to load into the grid. These are mostly large and non-square to
107 * show the scaling. */
108 const char* IMAGE_PATHS[] = {
110 DEMO_IMAGE_DIR "dali-logo.png",
111 DEMO_IMAGE_DIR "com.samsung.dali-demo.ico",
112 DEMO_IMAGE_DIR "square_primitive_shapes.bmp",
113 DEMO_IMAGE_DIR "gallery-large-14.wbmp",
115 // Images that show aspect ratio changes clearly in primitive shapes:
117 DEMO_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
118 DEMO_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
120 // Images from other demos that are tall, wide or just large:
122 DEMO_IMAGE_DIR "gallery-large-1.jpg",
123 DEMO_IMAGE_DIR "gallery-large-2.jpg",
124 DEMO_IMAGE_DIR "gallery-large-3.jpg",
125 DEMO_IMAGE_DIR "gallery-large-4.jpg",
126 DEMO_IMAGE_DIR "gallery-large-5.jpg",
127 DEMO_IMAGE_DIR "gallery-large-6.jpg",
128 DEMO_IMAGE_DIR "gallery-large-7.jpg",
129 DEMO_IMAGE_DIR "gallery-large-8.jpg",
130 DEMO_IMAGE_DIR "gallery-large-9.jpg",
131 DEMO_IMAGE_DIR "gallery-large-10.jpg",
132 DEMO_IMAGE_DIR "gallery-large-11.jpg",
133 DEMO_IMAGE_DIR "gallery-large-12.jpg",
134 DEMO_IMAGE_DIR "gallery-large-13.jpg",
135 DEMO_IMAGE_DIR "gallery-large-14.jpg",
136 DEMO_IMAGE_DIR "gallery-large-15.jpg",
137 DEMO_IMAGE_DIR "gallery-large-16.jpg",
138 DEMO_IMAGE_DIR "gallery-large-17.jpg",
139 DEMO_IMAGE_DIR "gallery-large-18.jpg",
140 DEMO_IMAGE_DIR "gallery-large-19.jpg",
141 DEMO_IMAGE_DIR "gallery-large-20.jpg",
142 DEMO_IMAGE_DIR "gallery-large-21.jpg",
144 DEMO_IMAGE_DIR "background-1.jpg",
145 DEMO_IMAGE_DIR "background-2.jpg",
146 DEMO_IMAGE_DIR "background-3.jpg",
147 DEMO_IMAGE_DIR "background-4.jpg",
148 DEMO_IMAGE_DIR "background-5.jpg",
149 DEMO_IMAGE_DIR "background-blocks.jpg",
150 DEMO_IMAGE_DIR "background-magnifier.jpg",
152 DEMO_IMAGE_DIR "background-1.jpg",
153 DEMO_IMAGE_DIR "background-2.jpg",
154 DEMO_IMAGE_DIR "background-3.jpg",
155 DEMO_IMAGE_DIR "background-4.jpg",
156 DEMO_IMAGE_DIR "background-5.jpg",
157 DEMO_IMAGE_DIR "background-blocks.jpg",
158 DEMO_IMAGE_DIR "background-magnifier.jpg",
160 DEMO_IMAGE_DIR "book-landscape-cover-back.jpg",
161 DEMO_IMAGE_DIR "book-landscape-cover.jpg",
162 DEMO_IMAGE_DIR "book-landscape-p1.jpg",
163 DEMO_IMAGE_DIR "book-landscape-p2.jpg",
165 DEMO_IMAGE_DIR "book-portrait-cover.jpg",
166 DEMO_IMAGE_DIR "book-portrait-p1.jpg",
167 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;
173 * Creates an ImageView
175 * @param[in] filename The path of the image.
176 * @param[in] width The width of the image in pixels.
177 * @param[in] height The height of the image in pixels.
178 * @param[in] fittingMode The mode to use when scaling the image to fit the desired dimensions.
180 ImageView CreateImageView(const std::string& filename, int width, int height, Dali::FittingMode::Type fittingMode)
182 ImageView imageView = ImageView::New();
185 map[Toolkit::ImageVisual::Property::URL] = filename;
186 map[Toolkit::ImageVisual::Property::DESIRED_WIDTH] = width;
187 map[Toolkit::ImageVisual::Property::DESIRED_HEIGHT] = height;
188 map[Toolkit::ImageVisual::Property::FITTING_MODE] = fittingMode;
189 imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
191 imageView.SetProperty(Dali::Actor::Property::NAME, filename);
192 imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
193 imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
198 /** Cycle the scaling mode options. */
199 Dali::FittingMode::Type NextMode(const Dali::FittingMode::Type oldMode)
201 Dali::FittingMode::Type newMode = FittingMode::SHRINK_TO_FIT;
204 case FittingMode::SHRINK_TO_FIT:
205 newMode = FittingMode::SCALE_TO_FILL;
207 case FittingMode::SCALE_TO_FILL:
208 newMode = FittingMode::FIT_WIDTH;
210 case FittingMode::FIT_WIDTH:
211 newMode = FittingMode::FIT_HEIGHT;
213 case FittingMode::FIT_HEIGHT:
214 newMode = FittingMode::SHRINK_TO_FIT;
221 * Bundle an image path with the rectangle to pack it into.
223 struct ImageConfiguration
225 ImageConfiguration(const char* const imagePath, const Vector2 dims)
235 * Post-layout image data.
237 struct PositionedImage
239 PositionedImage(ImageConfiguration& config, unsigned x, unsigned y, Vector2 imageGridDimensions)
240 : configuration(config),
243 imageGridDims(imageGridDimensions)
247 ImageConfiguration configuration;
250 Vector2 imageGridDims;
256 * @brief The main class of the demo.
258 class ImageScalingIrregularGridController : public ConnectionTracker
261 ImageScalingIrregularGridController(Application& application)
262 : mApplication(application),
266 std::cout << "ImageScalingIrregularGridController::ImageScalingIrregularGridController" << std::endl;
268 // Connect to the Application's Init signal
269 mApplication.InitSignal().Connect(this, &ImageScalingIrregularGridController::Create);
272 ~ImageScalingIrregularGridController()
274 // Nothing to do here.
278 * Called everytime an ImageView has loaded it's image
280 void ResourceReadySignal(Toolkit::Control control)
283 // To allow fast startup, we only place a small number of ImageViews on window first
284 if(mImagesLoaded == INITIAL_IMAGES_TO_LOAD)
286 // Adding the ImageViews to the window will trigger loading of the Images
287 mGridActor.Add(mOffWindowImageViews);
292 * One-time setup in response to Application InitSignal.
294 void Create(Application& application)
296 std::cout << "ImageScalingIrregularGridController::Create" << std::endl;
298 // Get a handle to the window:
299 Window window = application.GetWindow();
301 // Connect to input event signals:
302 window.KeyEventSignal().Connect(this, &ImageScalingIrregularGridController::OnKeyEvent);
304 // Create a default view with a default tool bar:
305 mContentLayer = DemoHelper::CreateView(mApplication,
312 // Create an image scaling toggle button. (right of toolbar)
313 Toolkit::PushButton toggleScalingButton = Toolkit::PushButton::New();
314 toggleScalingButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, TOGGLE_SCALING_IMAGE);
315 toggleScalingButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, TOGGLE_SCALING_IMAGE_SELECTED);
316 toggleScalingButton.ClickedSignal().Connect(this, &ImageScalingIrregularGridController::OnToggleScalingTouched);
317 mToolBar.AddControl(toggleScalingButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
319 SetTitle(APPLICATION_TITLE);
321 mOffWindowImageViews = Actor::New();
322 mOffWindowImageViews.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
323 mOffWindowImageViews.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
324 mOffWindowImageViews.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
326 // Build the main content of the widow:
327 PopulateContentLayer(DEFAULT_SCALING_MODE);
331 * Build the main part of the application's view.
333 void PopulateContentLayer(const Dali::FittingMode::Type fittingMode)
335 Window window = mApplication.GetWindow();
336 Vector2 windowSize = window.GetSize();
339 Actor imageField = BuildImageField(windowSize.x, GRID_WIDTH, GRID_MAX_HEIGHT, fittingMode, fieldHeight);
341 mScrollView = ScrollView::New();
343 mScrollView.ScrollStartedSignal().Connect(this, &ImageScalingIrregularGridController::OnScrollStarted);
344 mScrollView.ScrollCompletedSignal().Connect(this, &ImageScalingIrregularGridController::OnScrollCompleted);
346 mScrollView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
347 mScrollView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
349 mScrollView.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
351 mScrollView.SetAxisAutoLock(true);
352 mScrollView.SetAxisAutoLockGradient(1.0f);
354 // Restrict scrolling to mostly vertical only, but with some horizontal wiggle-room:
356 RulerPtr rulerX = new FixedRuler(windowSize.width); //< Pull the view back to the grid's centre-line when touch is release using a snapping ruler.
357 rulerX->SetDomain(RulerDomain(windowSize.width * -0.125f, windowSize.width * 1.125f)); //< Scroll slightly left/right of image field.
358 mScrollView.SetRulerX(rulerX);
360 RulerPtr rulerY = new DefaultRuler(); //< Snap in multiples of a screen / window height
361 rulerY->SetDomain(RulerDomain(-fieldHeight * 0.5f + windowSize.height * 0.5f - GRID_CELL_PADDING, fieldHeight * 0.5f + windowSize.height * 0.5f + GRID_CELL_PADDING));
362 mScrollView.SetRulerY(rulerY);
364 mContentLayer.Add(mScrollView);
365 mScrollView.Add(imageField);
366 mGridActor = imageField;
368 // Create the scroll bar
369 mScrollBarVertical = ScrollBar::New(Toolkit::ScrollBar::VERTICAL);
370 mScrollBarVertical.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT);
371 mScrollBarVertical.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT);
372 mScrollBarVertical.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::HEIGHT);
373 mScrollBarVertical.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
374 mScrollView.Add(mScrollBarVertical);
376 mScrollBarHorizontal = ScrollBar::New(Toolkit::ScrollBar::HORIZONTAL);
377 mScrollBarHorizontal.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_LEFT);
378 mScrollBarHorizontal.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
379 mScrollBarHorizontal.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
380 mScrollBarHorizontal.SetProperty(Actor::Property::ORIENTATION, Quaternion(Quaternion(Radian(1.5f * Math::PI), Vector3::ZAXIS)));
381 mScrollView.Add(mScrollBarHorizontal);
383 mScrollView.OnRelayoutSignal().Connect(this, &ImageScalingIrregularGridController::OnScrollViewRelayout);
385 // Scroll to top of grid so first images loaded are on-screen:
386 mScrollView.ScrollTo(Vector2(0, -1000000));
389 void OnScrollViewRelayout(Actor actor)
391 // Make the height of the horizontal scroll bar to be the same as the width of scroll view.
392 mScrollBarHorizontal.SetProperty(Actor::Property::SIZE, Vector2(0.0f, mScrollView.GetRelayoutSize(Dimension::WIDTH)));
396 * Build a field of images scaled into a variety of shapes from very wide,
397 * through square, to very tall. The images are direct children of the Dali::Actor
400 Actor BuildImageField(const float fieldWidth,
401 const unsigned gridWidth,
402 const unsigned maxGridHeight,
403 Dali::FittingMode::Type fittingMode,
404 float& outFieldHeight)
406 // Generate the list of image configurations to be fitted into the field:
408 std::vector<ImageConfiguration> configurations;
409 configurations.reserve(NUM_IMAGE_PATHS * NUM_IMAGE_SIZES);
410 for(unsigned imageIndex = 0; imageIndex < NUM_IMAGE_PATHS; ++imageIndex)
412 for(unsigned dimensionsIndex = 0; dimensionsIndex < NUM_IMAGE_SIZES; ++dimensionsIndex)
414 configurations.push_back(ImageConfiguration(IMAGE_PATHS[imageIndex], IMAGE_SIZES[dimensionsIndex]));
417 // Stir-up the list to get some nice irregularity in the generated field:
418 unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
419 std::shuffle(configurations.begin(), configurations.end(), std::default_random_engine(seed));
420 seed = std::chrono::system_clock::now().time_since_epoch().count();
421 std::shuffle(configurations.begin(), configurations.end(), std::default_random_engine(seed));
423 // Place the images in the grid:
425 GridFlags grid(gridWidth, maxGridHeight);
426 std::vector<PositionedImage> placedImages;
428 for(std::vector<ImageConfiguration>::iterator config = configurations.begin(), end = configurations.end(); config != end; ++config)
430 unsigned cellX, cellY;
431 Vector2 imageGridDims;
433 // Allocate a region of the grid for the image:
434 bool allocated = grid.AllocateRegion(config->dimensions, cellX, cellY, imageGridDims);
437 #ifdef DEBUG_PRINT_DIAGNOSTICS
438 fprintf(stderr, "Failed to allocate image in grid with dims (%f, %f) and path: %s.\n", config->dimensions.x, config->dimensions.y, config->path);
443 placedImages.push_back(PositionedImage(*config, cellX, cellY, imageGridDims));
445 DALI_ASSERT_DEBUG(grid.DebugCheckGridValid() && "Cells were set more than once, indicating erroneous overlap in placing images on the grid.");
446 const unsigned actualGridHeight = grid.GetHighestUsedRow() + 1;
448 // Take the images images in the grid and turn their logical locations into
449 // coordinates in a frame defined by a parent actor:
451 Actor gridActor = Actor::New();
452 gridActor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
453 gridActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
454 gridActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
456 // Work out the constants of the grid and cell dimensions and positions:
457 const float cellWidth = fieldWidth / gridWidth;
458 const float cellHeight = cellWidth / CELL_ASPECT_RATIO;
459 const Vector2 cellSize = Vector2(cellWidth, cellHeight);
460 outFieldHeight = actualGridHeight * cellHeight;
461 const Vector2 gridOrigin = Vector2(-fieldWidth * 0.5f, -outFieldHeight * 0.5);
463 unsigned int count = 0;
464 // Build the image actors in their right locations in their parent's frame:
465 for(std::vector<PositionedImage>::const_iterator i = placedImages.begin(), end = placedImages.end(); i != end; ++i, ++count)
467 const PositionedImage& imageSource = *i;
468 const Vector2 imageSize = imageSource.imageGridDims * cellSize - Vector2(GRID_CELL_PADDING * 2, GRID_CELL_PADDING * 2);
469 const Vector2 imageRegionCorner = gridOrigin + cellSize * Vector2(imageSource.cellX, imageSource.cellY);
470 const Vector2 imagePosition = imageRegionCorner + Vector2(GRID_CELL_PADDING, GRID_CELL_PADDING) + imageSize * 0.5f;
472 ImageView image = CreateImageView(imageSource.configuration.path, imageSize.x, imageSize.y, fittingMode);
473 image.SetProperty(Actor::Property::POSITION, Vector3(imagePosition.x, imagePosition.y, 0));
474 image.SetProperty(Actor::Property::SIZE, imageSize);
475 image.TouchedSignal().Connect(this, &ImageScalingIrregularGridController::OnTouchImage);
476 image.ResourceReadySignal().Connect(this, &ImageScalingIrregularGridController::ResourceReadySignal);
477 mFittingModes[image.GetProperty<int>(Actor::Property::ID)] = fittingMode;
478 mResourceUrls[image.GetProperty<int>(Actor::Property::ID)] = imageSource.configuration.path;
479 mSizes[image.GetProperty<int>(Actor::Property::ID)] = imageSize;
480 if(count < INITIAL_IMAGES_TO_LOAD)
482 gridActor.Add(image);
486 // Store the ImageView in an offwindow actor until the inital batch of ImageViews have finished loading their images
488 mOffWindowImageViews.Add(image);
496 * Upon Touching an image (Release), change its scaling mode and make it spin, provided we're not scrolling.
497 * @param[in] actor The actor touched
498 * @param[in] event The Touch information.
500 bool OnTouchImage(Actor actor, const TouchEvent& event)
502 if((event.GetPointCount() > 0) && (!mScrolling))
504 if(event.GetState(0) == PointState::UP)
506 // Spin the image a few times:
507 Animation animation = Animation::New(SPIN_DURATION);
508 animation.AnimateBy(Property(actor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360.0f * SPIN_DURATION)), Vector3::XAXIS), AlphaFunction::EASE_OUT);
511 // Change the scaling mode:
512 const unsigned id = actor.GetProperty<int>(Actor::Property::ID);
513 Dali::FittingMode::Type newMode = NextMode(mFittingModes[id]);
514 const Vector2 imageSize = mSizes[actor.GetProperty<int>(Actor::Property::ID)];
516 ImageView imageView = ImageView::DownCast(actor);
520 map[Visual::Property::TYPE] = Visual::IMAGE;
521 map[ImageVisual::Property::URL] = mResourceUrls[id];
522 map[ImageVisual::Property::DESIRED_WIDTH] = imageSize.width + 0.5f;
523 map[ImageVisual::Property::DESIRED_HEIGHT] = imageSize.height + 0.5f;
524 map[ImageVisual::Property::FITTING_MODE] = newMode;
525 imageView.SetProperty(ImageView::Property::IMAGE, map);
528 mFittingModes[id] = newMode;
535 * Main key event handler.
536 * Quit on escape key.
538 void OnKeyEvent(const KeyEvent& event)
540 if(event.GetState() == KeyEvent::DOWN)
542 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
550 * Signal handler, called when the 'Scaling' button has been touched.
552 * @param[in] button The button that was pressed.
554 bool OnToggleScalingTouched(Button button)
556 const unsigned numChildren = mGridActor.GetChildCount();
558 for(unsigned i = 0; i < numChildren; ++i)
560 ImageView gridImageView = ImageView::DownCast(mGridActor.GetChildAt(i));
563 // Cycle the scaling mode options:
564 unsigned int id = gridImageView.GetProperty<int>(Actor::Property::ID);
566 const Vector2 imageSize = mSizes[id];
567 Dali::FittingMode::Type newMode = NextMode(mFittingModes[id]);
570 map[Visual::Property::TYPE] = Visual::IMAGE;
571 map[ImageVisual::Property::URL] = mResourceUrls[id];
572 map[ImageVisual::Property::DESIRED_WIDTH] = imageSize.width;
573 map[ImageVisual::Property::DESIRED_HEIGHT] = imageSize.height;
574 map[ImageVisual::Property::FITTING_MODE] = newMode;
575 gridImageView.SetProperty(ImageView::Property::IMAGE, map);
577 mFittingModes[id] = newMode;
579 SetTitle(std::string(newMode == FittingMode::SHRINK_TO_FIT ? "SHRINK_TO_FIT" : newMode == FittingMode::SCALE_TO_FILL ? "SCALE_TO_FILL"
580 : newMode == FittingMode::FIT_WIDTH ? "FIT_WIDTH"
588 * Sets/Updates the title of the View
589 * @param[in] title The new title for the view.
591 void SetTitle(const std::string& title)
595 mTitleActor = DemoHelper::CreateToolBarLabel("");
596 // Add title to the tool bar.
597 mToolBar.AddControl(mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HORIZONTAL_CENTER);
600 mTitleActor.SetProperty(TextLabel::Property::TEXT, title);
604 * When scroll starts (i.e. user starts to drag scrollview),
605 * note this state (mScrolling = true)
606 * @param[in] position Current Scroll Position
608 void OnScrollStarted(const Vector2& position)
614 * When scroll starts (i.e. user stops dragging scrollview, and scrollview has snapped to destination),
615 * note this state (mScrolling = false).
616 * @param[in] position Current Scroll Position
618 void OnScrollCompleted(const Vector2& position)
624 Application& mApplication;
626 Layer mContentLayer; ///< The content layer (contains non gui chrome actors)
627 Toolkit::Control mView; ///< The View instance.
628 Toolkit::ToolBar mToolBar; ///< The View's Toolbar.
629 TextLabel mTitleActor; ///< The Toolbar's Title.
630 Actor mGridActor; ///< The container for the grid of images
631 Actor mOffWindowImageViews; ///< ImageViews held off window until the inital batch have loaded their images
632 ScrollView mScrollView; ///< ScrollView UI Component
633 ScrollBar mScrollBarVertical;
634 ScrollBar mScrollBarHorizontal;
635 bool mScrolling; ///< ScrollView scrolling state (true = scrolling, false = stationary)
636 std::map<unsigned, Dali::FittingMode::Type> mFittingModes; ///< Stores the current scaling mode of each image, keyed by image actor id.
637 std::map<unsigned, std::string> mResourceUrls; ///< Stores the url of each image, keyed by image actor id.
638 std::map<unsigned, Vector2> mSizes; ///< Stores the current size of each image, keyed by image actor id.
639 unsigned int mImagesLoaded; ///< How many images have been loaded
642 int DALI_EXPORT_API main(int argc, char** argv)
644 Application application = Application::New(&argc, &argv, DEMO_THEME_PATH);
645 ImageScalingIrregularGridController test(application);
646 application.MainLoop();