Image Load-time Fitting and Sampling Modes Example 81/36381/10
authorAndrew Cox <andrew.cox@partner.samsung.com>
Mon, 2 Mar 2015 15:39:36 +0000 (15:39 +0000)
committerAndrew Cox <andrew.cox@partner.samsung.com>
Fri, 24 Apr 2015 17:13:01 +0000 (18:13 +0100)
Change-Id: I8558b0e432cbbf2470fc9b80b4178d20663b3758
Signed-off-by: Andrew Cox <andrew.cox@partner.samsung.com>
com.samsung.dali-demo.xml
demo/dali-demo.cpp
examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp [new file with mode: 0644]
resources/style/demo-theme.json
resources/style/mobile/demo-theme.json
shared/dali-demo-strings.h

index c68fba7..3ced582 100644 (file)
@@ -53,8 +53,8 @@
                <label>Refraction effect</label>
        </ui-application>
        <ui-application appid="scripting.example" exec="/usr/apps/com.samsung.dali-demo/bin/scripting.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
-    <label>Scroll View</label>
-  </ui-application>
+               <label>Scroll View</label>
+       </ui-application>
        <ui-application appid="scroll-view.example" exec="/usr/apps/com.samsung.dali-demo/bin/scroll-view.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
                <label>Scroll View</label>
        </ui-application>
        <ui-application appid="builder.example" exec="/usr/apps/com.samsung.dali-demo/bin/builder.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
                <label>Script Based UI</label>
        </ui-application>
+       <ui-application appid="image-scaling-and-filtering.example" exec="/usr/apps/com.samsung.dali-demo/bin/image-scaling-and-filtering.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
+               <label>Image Fitting and Sampling</label>
+       </ui-application>
        <ui-application appid="image-scaling-irregular-grid.example" exec="/usr/apps/com.samsung.dali-demo/bin/image-scaling-irregular-grid.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
-               <label>Image Scaling Modes</label>
+               <label>Image Scaling Grid</label>
        </ui-application>
        <ui-application appid="buttons.example" exec="/usr/apps/com.samsung.dali-demo/bin/buttons.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
                <label>Buttons</label>
index 63d8b69..78c2aae 100644 (file)
@@ -51,6 +51,7 @@ int main(int argc, char **argv)
   demo.AddExample(Example("scroll-view.example", DALI_DEMO_STR_TITLE_SCROLL_VIEW));
   demo.AddExample(Example("shadow-bone-lighting.example", DALI_DEMO_STR_TITLE_LIGHTS_AND_SHADOWS));
   demo.AddExample(Example("builder.example", DALI_DEMO_STR_TITLE_SCRIPT_BASED_UI));
+  demo.AddExample(Example("image-scaling-and-filtering.example", DALI_DEMO_STR_TITLE_IMAGE_FITTING_SAMPLING));
   demo.AddExample(Example("image-scaling-irregular-grid.example", DALI_DEMO_STR_TITLE_IMAGE_SCALING));
   demo.AddExample(Example("text-label.example", DALI_DEMO_STR_TITLE_TEXT_LABEL));
   demo.AddExample(Example("text-label-multi-language.example", DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE));
diff --git a/examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp b/examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp
new file mode 100644 (file)
index 0000000..882687a
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include "shared/view.h"
+#include <iostream>
+
+using namespace Dali;
+using Toolkit::TextLabel;
+
+namespace
+{
+
+const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
+const Vector4 BACKGROUND_COLOUR( 1.0f, 1.0f, 1.0f, 0.15f );
+
+const int MARGIN_SIZE = 10;
+
+const char* const NEXT_BUTTON_ID = "NEXT_BUTTON";
+const char* const PREVIOUS_BUTTON_ID = "PREVIOUS_BUTTON";
+const char * const DALI_ICON_PLAY = DALI_IMAGE_DIR "icon-play.png";
+
+const char* const PUSHBUTTON_PRESS_IMAGE = DALI_IMAGE_DIR "button-down.9.png";
+const char* const PUSHBUTTON_BUTTON_IMAGE = DALI_IMAGE_DIR "button-up.9.png";
+const char* const PUSHBUTTON_DISABLED_IMAGE = DALI_IMAGE_DIR "button-disabled.9.png";
+
+const char* const FITTING_BUTTON_ID = "FITTING_BUTTON";
+const char* const SAMPLING_BUTTON_ID = "SAMPLING_BUTTON";
+const char* const FITTING_BUTTON_TEXT = "Fitting";
+const char* const SAMPLING_BUTTON_TEXT = "Sampling";
+
+const char* const STYLE_LABEL_TEXT  = "grouplabel";
+const char* const STYLE_BUTTON_TEXT = "buttonlabel";
+
+
+
+const char* IMAGE_PATHS[] =
+{
+  // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered
+  // black and white image:
+  DALI_IMAGE_DIR "gallery-large-14.wbmp",
+  // Variety of sizes, shapes and formats:
+  DALI_IMAGE_DIR "animation-list.png",
+  DALI_IMAGE_DIR "layer1.png",
+  DALI_IMAGE_DIR "layer2.png",
+  DALI_IMAGE_DIR "music-libray-main-screen.png",
+  DALI_IMAGE_DIR "music-libray-record-cover.png",
+  DALI_IMAGE_DIR "contacts-background.png",
+  DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
+  DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
+  DALI_IMAGE_DIR "square_primitive_shapes.bmp",
+  DALI_IMAGE_DIR "dali-logo.png",
+  DALI_IMAGE_DIR "com.samsung.dali-demo.ico",
+  DALI_IMAGE_DIR "gallery-large-14.jpg",
+  DALI_IMAGE_DIR "book-landscape-cover.jpg",
+  DALI_IMAGE_DIR "book-portrait-p1.jpg",
+  DALI_IMAGE_DIR "book-landscape-cover-back.jpg",
+  DALI_IMAGE_DIR "background-1.jpg",
+  DALI_IMAGE_DIR "background-blocks.jpg",
+  DALI_IMAGE_DIR "background-magnifier.jpg",
+  DALI_IMAGE_DIR "gallery-large-14.jpg",
+  NULL
+};
+const int NUM_IMAGE_PATHS = sizeof(IMAGE_PATHS) / sizeof(IMAGE_PATHS[0]) - 1u;
+
+/** Cycle the scaling mode options. */
+FittingMode::Type NextScalingMode( FittingMode::Type oldMode )
+{
+  FittingMode::Type newMode = FittingMode::SHRINK_TO_FIT;
+  switch ( oldMode )
+  {
+    case FittingMode::SHRINK_TO_FIT:
+      newMode = FittingMode::SCALE_TO_FILL;
+      break;
+    case FittingMode::SCALE_TO_FILL:
+      newMode = FittingMode::FIT_WIDTH;
+      break;
+    case FittingMode::FIT_WIDTH:
+      newMode = FittingMode::FIT_HEIGHT;
+      break;
+    case FittingMode::FIT_HEIGHT:
+      newMode = FittingMode::SHRINK_TO_FIT;
+      break;
+  }
+  return newMode;
+}
+
+/** Cycle through filter mode options. */
+SamplingMode::Type NextFilterMode( SamplingMode::Type oldMode )
+{
+  SamplingMode::Type newMode = SamplingMode::BOX;
+
+  switch ( oldMode )
+  {
+    case SamplingMode::BOX:
+      newMode = SamplingMode::NEAREST;
+      break;
+    case SamplingMode::NEAREST:
+      newMode = SamplingMode::LINEAR;
+      break;
+    case SamplingMode::LINEAR:
+      newMode = SamplingMode::BOX_THEN_NEAREST;
+      break;
+    case SamplingMode::BOX_THEN_NEAREST:
+      newMode = SamplingMode::BOX_THEN_LINEAR;
+      break;
+    case SamplingMode::BOX_THEN_LINEAR:
+      newMode = SamplingMode::NO_FILTER;
+      break;
+    case SamplingMode::NO_FILTER:
+      newMode = SamplingMode::BOX;
+      break;
+    case SamplingMode::DONT_CARE:
+      newMode = SamplingMode::BOX;
+      break;
+  }
+  return newMode;
+}
+
+const char* StringFromScalingMode( FittingMode::Type scalingMode )
+{
+  return scalingMode == FittingMode::SCALE_TO_FILL ? "SCALE_TO_FILL" : scalingMode == FittingMode::SHRINK_TO_FIT ? "SHRINK_TO_FIT" : scalingMode == FittingMode::FIT_WIDTH ? "FIT_WIDTH" : scalingMode == FittingMode::FIT_HEIGHT ? "FIT_HEIGHT" : "UnknownScalingMode";
+}
+
+const char* StringFromFilterMode( SamplingMode::Type filterMode )
+{
+  return filterMode == SamplingMode::BOX ? "BOX" : filterMode == SamplingMode::BOX_THEN_NEAREST ? "BOX_THEN_NEAREST" : filterMode == SamplingMode::BOX_THEN_LINEAR ? "BOX_THEN_LINEAR" : filterMode == SamplingMode::NEAREST ? "NEAREST" : filterMode == SamplingMode::LINEAR ? "LINEAR" : filterMode == SamplingMode::NO_FILTER ? "NO_FILTER" : filterMode == SamplingMode::DONT_CARE ? "DONT_CARE" : "UnknownFilterMode";
+}
+
+}
+
+// This example shows the load-time image scaling and filtering features.
+//
+class ImageScalingAndFilteringController : public ConnectionTracker
+{
+public:
+
+  ImageScalingAndFilteringController( Application& application )
+  : mApplication( application ),
+    mImageStageScale( 0.5f, 0.5f ),
+    mCurrentPath( 0 ),
+    mFittingMode( FittingMode::SCALE_TO_FILL ),
+    mSamplingMode( SamplingMode::BOX_THEN_LINEAR)
+  {
+    // Connect to the Application's Init signal
+    mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create );
+  }
+
+  ~ImageScalingAndFilteringController()
+  {
+    // Nothing to do here;
+  }
+
+  // The Init signal is received once (only) during the Application lifetime
+  void Create( Application& application )
+  {
+    // Apply the default theme:
+    DemoHelper::RequestThemeChange();
+
+    // Get a handle to the stage
+    Stage stage = Stage::GetCurrent();
+
+    // Background image:
+    ResourceImage backgroundImage = ResourceImage::New( BACKGROUND_IMAGE, ImageDimensions( stage.GetSize().width, stage.GetSize().height ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR );
+    ImageActor background = ImageActor::New( backgroundImage );
+    background.SetZ( -2.0f );
+    background.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    background.SetSize( stage.GetSize() );
+    stage.Add( background );
+
+    // Make grey pixels for the desired box, the desired height the desired width:
+    BufferImage desiredBackground = BufferImage::WHITE();
+
+    BufferImage heightBackground = BufferImage::WHITE();
+    PixelBuffer* const heightPixel = heightBackground.GetBuffer();
+    heightPixel[0] = 0x8f;
+    heightPixel[1] = 0x8f;
+    heightPixel[2] = 0x8f;
+
+    BufferImage widthBackground = BufferImage::WHITE();
+    PixelBuffer* const widthPixel = widthBackground.GetBuffer();
+    widthPixel[0] = 0x4f;
+    widthPixel[1] = 0x4f;
+    widthPixel[2] = 0x4f;
+
+    mHeightBox = ImageActor::New( heightBackground );
+    mHeightBox.SetOpacity( 0.2f );
+    stage.Add( mHeightBox );
+
+    mWidthBox = ImageActor::New( widthBackground );
+    mWidthBox.SetOpacity( 0.2f );
+    stage.Add( mWidthBox );
+
+    mDesiredBox = ImageActor::New( desiredBackground );
+    stage.Add( mDesiredBox );
+
+    mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
+    mDesiredBox.SetParentOrigin( ParentOrigin::CENTER );
+    mDesiredBox.SetAnchorPoint( AnchorPoint::CENTER );
+    mDesiredBox.SetPosition( 0, 0, -1 );
+
+    mHeightBox.SetSize( stage.GetSize().width,  (stage.GetSize() * mImageStageScale).height );
+    mHeightBox.SetParentOrigin( ParentOrigin::CENTER );
+    mHeightBox.SetAnchorPoint( AnchorPoint::CENTER );
+    mHeightBox.SetPosition( 0, 0, -1 );
+
+    mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
+    mWidthBox.SetParentOrigin( ParentOrigin::CENTER );
+    mWidthBox.SetAnchorPoint( AnchorPoint::CENTER );
+    mWidthBox.SetPosition( 0, 0, -1 );
+
+    // Make a grab-handle for resizing the image:
+    mGrabCorner = Toolkit::PushButton::New();
+    mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
+    mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+    mGrabCorner.SetSelectedImage( Dali::ResourceImage::New( PUSHBUTTON_PRESS_IMAGE ) );
+    mGrabCorner.SetButtonImage( Dali::ResourceImage::New( PUSHBUTTON_BUTTON_IMAGE ) );
+    mGrabCorner.SetDisabledImage( Dali::ResourceImage::New( PUSHBUTTON_DISABLED_IMAGE ) );
+    mGrabCorner.SetName( "GrabCorner" );
+    mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
+    mGrabCorner.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
+    mGrabCorner.SetSize( Vector2( stage.GetSize().width*0.08f, stage.GetSize().width*0.08f ) );
+    mGrabCorner.SetZ( 1.0f );
+    mGrabCorner.SetOpacity( 0.6f );
+    mDesiredBox.Add( mGrabCorner );
+    mPanGestureDetector = PanGestureDetector::New();
+    mPanGestureDetector.Attach( mGrabCorner );
+    mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan );
+
+    // Initialize the actor
+    mImageActor = ImageActor::New();
+
+    // Reposition the actor
+    mImageActor.SetParentOrigin( ParentOrigin::CENTER );
+    mImageActor.SetAnchorPoint( AnchorPoint::CENTER );
+
+    // Display the actor on the stage
+    stage.Add( mImageActor );
+
+    mImageActor.SetSize( stage.GetSize() * mImageStageScale );
+
+    // Setup the pinch detector for scaling the desired image load dimensions:
+    mPinchDetector = PinchGestureDetector::New();
+    mPinchDetector.Attach( mImageActor );
+    mPinchDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPinch );
+
+    // Tie-in input event handlers:
+    stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent );
+
+    CreateControls();
+
+    ResizeImage();
+  }
+
+  /**
+   * Create the GUI controls which float above the scene
+   */
+  void CreateControls()
+  {
+    Stage stage = Stage::GetCurrent();
+
+    Dali::Layer controlsLayer = Dali::Layer::New();
+    controlsLayer.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    controlsLayer.SetSizeModeFactor( Vector3( 1.0f, 1.0f, 1.0f ) );
+    controlsLayer.SetAnchorPoint( AnchorPoint::TOP_LEFT);
+    controlsLayer.SetParentOrigin( ParentOrigin::TOP_LEFT);
+    stage.Add( controlsLayer );
+
+    // Back and next image buttons in corners of stage:
+    unsigned int playWidth = std::min( stage.GetSize().x * (1 / 5.0f), 58.0f );
+    Image playImage = ResourceImage::New( DALI_ICON_PLAY, ImageDimensions( playWidth, playWidth ), FittingMode::SHRINK_TO_FIT, SamplingMode::BOX_THEN_LINEAR );
+    Actor imagePrevious = ImageActor::New( playImage );
+
+    // Last image button:
+    imagePrevious.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    imagePrevious.RotateBy( Radian(3.14159265358979323846f), Vector3( 0, 1.0f, 0 ) );
+    imagePrevious.SetY( playWidth * 0.5f );
+    imagePrevious.SetX( playWidth + playWidth * 0.5f );
+    imagePrevious.SetOpacity( 0.6f );
+    controlsLayer.Add( imagePrevious );
+    imagePrevious.SetName( PREVIOUS_BUTTON_ID );
+    imagePrevious.TouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnControlTouched );
+
+    // Next image button:
+    Actor imageNext = ImageActor::New( playImage );
+    imageNext.SetAnchorPoint( AnchorPoint::TOP_RIGHT );
+    imageNext.SetY( playWidth * 0.5f );
+    imageNext.SetX( stage.GetSize().x - playWidth * 0.5f );
+    imageNext.SetOpacity( 0.6f );
+    controlsLayer.Add( imageNext );
+    imageNext.SetName( NEXT_BUTTON_ID );
+    imageNext.TouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnControlTouched );
+
+    // Buttons to popup selectors for fitting and sampling modes:
+
+    // Wrapper table to hold two buttons side by side:
+    Toolkit::TableView modesGroupBackground = Toolkit::TableView::New( 1, 2 );
+    modesGroupBackground.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+    modesGroupBackground.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+    modesGroupBackground.SetBackgroundColor( BACKGROUND_COLOUR );
+    modesGroupBackground.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE ) );
+    modesGroupBackground.SetFitHeight( 0 );
+
+    modesGroupBackground.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
+    modesGroupBackground.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
+    modesGroupBackground.SetPosition( 0.0f, 0.0f );
+
+    controlsLayer.Add( modesGroupBackground );
+
+    {
+      // Vertical table to hold label and button:
+      Toolkit::TableView fittingModeGroup = Toolkit::TableView::New( 2, 1 );
+      fittingModeGroup.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+      fittingModeGroup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+      fittingModeGroup.SetBackgroundColor( BACKGROUND_COLOUR );
+      fittingModeGroup.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE * 0.5f ) );
+      fittingModeGroup.SetFitHeight( 0 );
+      fittingModeGroup.SetFitHeight( 1 );
+
+      TextLabel label = TextLabel::New( "Image fitting mode:" );
+      label.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_LABEL_TEXT );
+      fittingModeGroup.Add( label );
+
+      Toolkit::PushButton button = CreateButton( FITTING_BUTTON_ID, StringFromScalingMode( mFittingMode ) );
+      button.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      fittingModeGroup.Add( button );
+      mFittingModeButton = button;
+
+      modesGroupBackground.Add( fittingModeGroup );
+    }
+
+    {
+      // Vertical table to hold label and button:
+      Toolkit::TableView samplingModeGroup = Toolkit::TableView::New( 2, 1 );
+      samplingModeGroup.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+      samplingModeGroup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+      samplingModeGroup.SetBackgroundColor( BACKGROUND_COLOUR );
+      samplingModeGroup.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE * 0.5f ) );
+      samplingModeGroup.SetFitHeight( 0 );
+      samplingModeGroup.SetFitHeight( 1 );
+
+      TextLabel label = TextLabel::New( "Image sampling mode:" );
+      label.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_LABEL_TEXT );
+      samplingModeGroup.Add( label );
+
+      Toolkit::PushButton button = CreateButton( SAMPLING_BUTTON_ID, StringFromFilterMode( mSamplingMode ) );
+      button.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      samplingModeGroup.Add( button );
+      mSamplingModeButton = button;
+
+      modesGroupBackground.Add( samplingModeGroup );
+    }
+  }
+
+  Toolkit::PushButton CreateButton( const char * id, const char * label )
+  {
+    Toolkit::PushButton button = Toolkit::PushButton::New();
+    button.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+    button.SetName( id );
+    button.SetLabel( label );
+    button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+    button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+    button.SetSelectedImage( Dali::ResourceImage::New( PUSHBUTTON_PRESS_IMAGE ) );
+    button.SetButtonImage( Dali::ResourceImage::New( PUSHBUTTON_BUTTON_IMAGE ) );
+    button.SetDisabledImage( Dali::ResourceImage::New( PUSHBUTTON_DISABLED_IMAGE ) );
+    button.ClickedSignal().Connect( this, &ImageScalingAndFilteringController::OnButtonClicked );
+    return button;
+  }
+
+  Toolkit::Popup CreatePopup()
+  {
+    Stage stage = Stage::GetCurrent();
+    const float POPUP_WIDTH_DP = stage.GetSize().width * 0.75f;
+
+    Toolkit::Popup popup = Toolkit::Popup::New();
+    popup.SetName( "POPUP" );
+    popup.SetParentOrigin( ParentOrigin::CENTER );
+    popup.SetAnchorPoint( AnchorPoint::CENTER );
+    popup.SetSize( POPUP_WIDTH_DP, 0.0f );
+    popup.HideTail();
+
+    popup.OutsideTouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnPopupOutsideTouched );
+
+    return popup;
+  }
+
+  //void CreatePopupButton( Toolkit::Popup popup, const char* id )
+  Toolkit::PushButton CreatePopupButton( Actor parent, const char* id )
+  {
+    Toolkit::PushButton button = Toolkit::PushButton::New();
+    button.SetName( id );
+    button.SetLabel( id );
+    button.SetSelectedImage( Dali::ResourceImage::New( PUSHBUTTON_PRESS_IMAGE ) );
+    button.SetButtonImage( Dali::ResourceImage::New( PUSHBUTTON_BUTTON_IMAGE ) );
+    Toolkit::TextLabel textLabel = Toolkit::TextLabel::DownCast( button.GetLabel() );
+    textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 12.0f );
+
+    button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    button.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
+    button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+    button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+
+    button.ClickedSignal().Connect( this, &ImageScalingAndFilteringController::OnButtonClicked );
+
+    parent.Add( button );
+    return button;
+  }
+
+  bool OnButtonClicked( Toolkit::Button button )
+  {
+    if( button.GetName() == FITTING_BUTTON_ID )
+    {
+      mPopup = CreatePopup();
+
+      // Four-row table to hold buttons:
+      Toolkit::TableView fittingModes = Toolkit::TableView::New( 4, 1 );
+      fittingModes.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+      fittingModes.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+      fittingModes.SetBackgroundColor( BACKGROUND_COLOUR );
+      fittingModes.SetCellPadding( Size( MARGIN_SIZE, MARGIN_SIZE * 0.5 ) );
+      fittingModes.SetFitHeight( 0 );
+      fittingModes.SetFitHeight( 1 );
+      fittingModes.SetFitHeight( 2 );
+      fittingModes.SetFitHeight( 3 );
+
+      CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::SCALE_TO_FILL ) );
+      CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::SHRINK_TO_FIT ) );
+      CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::FIT_WIDTH ) );
+      CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::FIT_HEIGHT ) );
+
+      mPopup.Add( fittingModes );
+      mPopup.Show();
+    }
+    else if( button.GetName() == SAMPLING_BUTTON_ID )
+    {
+      mPopup = CreatePopup();
+
+      // Table to hold buttons for each sampling mode:
+      Toolkit::TableView samplingModes = Toolkit::TableView::New( 6, 1 );
+      samplingModes.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+      samplingModes.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+      samplingModes.SetBackgroundColor( BACKGROUND_COLOUR );
+      samplingModes.SetCellPadding( Size( MARGIN_SIZE, MARGIN_SIZE * 0.5 ) );
+      samplingModes.SetFitHeight( 0 );
+      samplingModes.SetFitHeight( 1 );
+      samplingModes.SetFitHeight( 2 );
+      samplingModes.SetFitHeight( 3 );
+      samplingModes.SetFitHeight( 4 );
+      samplingModes.SetFitHeight( 5 );
+
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::NEAREST ) );
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::LINEAR ) );
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX ) );
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX_THEN_NEAREST ) );
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX_THEN_LINEAR ) );
+      CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::NO_FILTER ) );
+
+      mPopup.Add( samplingModes );
+      mPopup.Show();
+    }
+    else if( CheckFittingModeButton( button, FittingMode::SCALE_TO_FILL) ||
+             CheckFittingModeButton( button, FittingMode::SHRINK_TO_FIT) ||
+             CheckFittingModeButton( button, FittingMode::FIT_WIDTH) ||
+             CheckFittingModeButton( button, FittingMode::FIT_HEIGHT) )
+    {
+    }
+    else if( CheckSamplingModeButton( button, SamplingMode::NEAREST ) ||
+             CheckSamplingModeButton( button, SamplingMode::LINEAR ) ||
+             CheckSamplingModeButton( button, SamplingMode::BOX ) ||
+             CheckSamplingModeButton( button, SamplingMode::LINEAR ) ||
+             CheckSamplingModeButton( button, SamplingMode::BOX_THEN_NEAREST ) ||
+             CheckSamplingModeButton( button, SamplingMode::BOX_THEN_LINEAR ) ||
+             CheckSamplingModeButton( button, SamplingMode::NO_FILTER ) )
+    {
+    }
+    return true;
+  }
+
+  bool CheckFittingModeButton( Actor &button, FittingMode::Type mode )
+  {
+    const char * const modeName = StringFromScalingMode( mode );
+    if( button.GetName() == modeName )
+    {
+      mFittingMode = mode;
+      mFittingModeButton.SetLabel( modeName );
+      mFittingModeButton.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      ResizeImage();
+      mPopup.Hide();
+      mPopup.Reset();
+      return true;
+    }
+    return false;
+  }
+
+  bool CheckSamplingModeButton( Actor &button, SamplingMode::Type mode )
+  {
+    const char * const modeName = StringFromFilterMode( mode );
+    if( button.GetName() == modeName )
+    {
+      mSamplingMode = mode;
+      mSamplingModeButton.SetLabel( modeName );
+      mSamplingModeButton.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      ResizeImage();
+      mPopup.Hide();
+      mPopup.Reset();
+      return true;
+    }
+    return false;
+  }
+
+  void OnPopupOutsideTouched()
+  {
+    if( mPopup )
+    {
+      mPopup.Hide();
+      mPopup.Reset();
+    }
+  }
+
+  void OnImageLoaded( ResourceImage image )
+  {
+      DALI_ASSERT_DEBUG( image == mNextImage );
+      mImageActor.SetImage( image );
+      mImageActor.SetSize( Size( image.GetWidth(), image.GetHeight() ) );
+  }
+
+  bool OnControlTouched( Actor actor, const TouchEvent& event )
+  {
+    if(event.GetPointCount() > 0)
+    {
+      const TouchPoint& point = event.GetPoint(0);
+      switch(point.state)
+      {
+        case TouchPoint::Up:
+        {
+          const std::string & name = actor.GetName();
+          if( name == NEXT_BUTTON_ID )
+          {
+            mCurrentPath = mCurrentPath + 1;
+            mCurrentPath = mCurrentPath <  NUM_IMAGE_PATHS ? mCurrentPath : 0;
+            ResizeImage();
+          }
+          else if( name == PREVIOUS_BUTTON_ID )
+          {
+            mCurrentPath = mCurrentPath - 1;
+            mCurrentPath = mCurrentPath >= 0 ? mCurrentPath : NUM_IMAGE_PATHS - 1;
+            ResizeImage();
+          }
+          break;
+        }
+        default:
+        {
+          break;
+        }
+      } // end switch
+    }
+
+    return false;
+  }
+
+  void OnPinch( Actor actor, const PinchGesture& pinch )
+  {
+    if( pinch.state == Gesture::Started )
+    {
+      mLastPinchScale = pinch.scale;
+    }
+    const float scale = pinch.scale;
+
+    if( scale != mLastPinchScale )
+    {
+      if ( scale < mLastPinchScale )
+      {
+        mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
+        mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
+      }
+      else
+      {
+        mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
+        mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
+      }
+      ResizeImage();
+    }
+    mLastPinchScale = scale;
+  }
+
+  void OnPan( Actor actor, const PanGesture& gesture )
+  {
+    Stage stage = Stage::GetCurrent();
+    mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x + (gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );
+    mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y + (gesture.displacement.y * 2.0f / stage.GetSize().height ) ) );
+    ResizeImage();
+  }
+
+  void OnKeyEvent(const KeyEvent& event)
+  {
+    if( event.state == KeyEvent::Down )
+    {
+      if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+      {
+        if( mPopup && mPopup.IsVisible() )
+        {
+          mPopup.Hide();
+          mPopup.Reset();
+        }
+        else
+        {
+          mApplication.Quit();
+        }
+      }
+      else if ( event.keyPressedName == "Right" )
+      {
+        mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
+      }
+      else if ( event.keyPressedName == "Left" )
+      {
+        mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
+      }
+      else if ( event.keyPressedName == "Up" )
+      {
+        mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
+      }
+      else if ( event.keyPressedName == "Down" )
+      {
+        mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
+      }
+      else if ( event.keyPressedName == "o" )
+      {
+        mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
+        mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
+      }
+      else if ( event.keyPressedName == "p" )
+      {
+        mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
+        mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
+      }
+      else if ( event.keyPressedName == "n" )
+      {
+        mCurrentPath = mCurrentPath + 1;
+        mCurrentPath = mCurrentPath <  NUM_IMAGE_PATHS ? mCurrentPath : 0;
+      }
+      else if ( event.keyPressedName == "b" )
+      {
+        mCurrentPath = mCurrentPath - 1;
+        mCurrentPath = mCurrentPath >= 0 ? mCurrentPath : NUM_IMAGE_PATHS - 1;
+      }
+      // Cycle filter and scaling modes:
+      else if ( event.keyPressedName == "f" )
+      {
+        mSamplingMode = NextFilterMode( mSamplingMode );
+        mSamplingModeButton.SetLabel( StringFromFilterMode( mSamplingMode ) );
+        mSamplingModeButton.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      }
+      // Cycle filter and scaling modes:
+      else if ( event.keyPressedName == "s" )
+      {
+        mFittingMode = NextScalingMode( mFittingMode );
+        mFittingModeButton.SetLabel( StringFromScalingMode( mFittingMode ) );
+        mFittingModeButton.GetLabel().SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
+      }
+      else
+      {
+        return;
+      }
+
+      ResizeImage();
+    }
+  }
+
+private:
+  void ResizeImage()
+  {
+    const char * const path = IMAGE_PATHS[mCurrentPath];
+
+    Stage stage = Stage::GetCurrent();
+    Size imageSize = stage.GetSize() * mImageStageScale;
+    const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x );
+
+    ResourceImage image = ResourceImage::New( path, imageSizeInt, mFittingMode, mSamplingMode );
+    image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded );
+
+    mNextImage = image;
+
+    mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
+    mHeightBox.SetSize( stage.GetSize().width,  (stage.GetSize() * mImageStageScale).height );
+    mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
+  }
+
+private:
+  Application&  mApplication;
+  Actor mDesiredBox; //< Background rectangle to show requested image size.
+  Actor mHeightBox;  //< Background horizontal stripe to show requested image height.
+  Actor mWidthBox;   //< Background vertical stripe to show requested image width.
+  Toolkit::PushButton mFittingModeButton;
+  Toolkit::PushButton mSamplingModeButton;
+  Toolkit::Popup mPopup;
+  PinchGestureDetector mPinchDetector;
+  float mLastPinchScale;
+  Toolkit::PushButton  mGrabCorner;
+  PanGestureDetector mPanGestureDetector;
+  ImageActor mImageActor;
+  ResourceImage mNextImage; //< Currently-loading image
+  Vector2 mImageStageScale;
+  int mCurrentPath;
+  FittingMode::Type mFittingMode;
+  SamplingMode::Type mSamplingMode;
+};
+
+void RunTest( Application& application )
+{
+  ImageScalingAndFilteringController test( application );
+
+  application.MainLoop();
+}
+
+// Entry point for Linux & Tizen applications
+int main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv );
+
+  RunTest( application );
+
+  return 0;
+}
index 89650ce..79acc25 100644 (file)
@@ -54,6 +54,16 @@ distributing this software or its derivatives.
     "scrollview":
     {
       "overshoot-effect-color":"B018"
+    },
+
+    "grouplabel":
+    {
+      "point-size":9
+    },
+
+    "buttonlabel":
+    {
+      "point-size":11
     }
   }
 }
index 682db8e..4328b32 100644 (file)
@@ -94,6 +94,16 @@ distributing this software or its derivatives.
     "scrollview":
     {
       "overshoot-effect-color":"B018"
+    },
+
+    "grouplabel":
+    {
+      "point-size":6
+    },
+
+    "buttonlabel":
+    {
+      "point-size":8
     }
   }
 }
index 56adecf..6f408d5 100644 (file)
@@ -47,6 +47,7 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_SCROLL_VIEW dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_SCROLL_VIEW")
 #define DALI_DEMO_STR_TITLE_LIGHTS_AND_SHADOWS dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_LIGHTS_AND_SHADOWS")
 #define DALI_DEMO_STR_TITLE_SCRIPT_BASED_UI dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_SCRIPT_BASED_UI")
+#define DALI_DEMO_STR_TITLE_IMAGE_FITTING_SAMPLING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_IMAGE_FITTING_SAMPLING")
 #define DALI_DEMO_STR_TITLE_IMAGE_SCALING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_IMAGE_SCALING")
 #define DALI_DEMO_STR_TITLE_TEXT_LABEL dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_TEXT_LABEL")
 #define DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE")
@@ -74,7 +75,8 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_SCROLL_VIEW               "Scroll View"
 #define DALI_DEMO_STR_TITLE_LIGHTS_AND_SHADOWS        "Lights and shadows"
 #define DALI_DEMO_STR_TITLE_SCRIPT_BASED_UI           "Script Based UI"
-#define DALI_DEMO_STR_TITLE_IMAGE_SCALING             "Image Scaling Modes"
+#define DALI_DEMO_STR_TITLE_IMAGE_FITTING_SAMPLING    "Image Fitting and Sampling"
+#define DALI_DEMO_STR_TITLE_IMAGE_SCALING             "Image Scaling Grid"
 #define DALI_DEMO_STR_TITLE_TEXT_LABEL                "Text Label"
 #define DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE "Text Scripts"
 #define DALI_DEMO_STR_TITLE_EMOJI_TEXT                "Emoji Text"