diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index c68fba7..3ced582 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -53,8 +53,8 @@ - - + + @@ -67,8 +67,11 @@ + + + - + diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp index 63d8b69..78c2aae 100644 --- a/demo/dali-demo.cpp +++ b/demo/dali-demo.cpp @@ -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 index 0000000..882687a --- /dev/null +++ b/examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp @@ -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 +#include +#include "shared/view.h" +#include + +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; +} diff --git a/resources/style/demo-theme.json b/resources/style/demo-theme.json index 89650ce..79acc25 100644 --- a/resources/style/demo-theme.json +++ b/resources/style/demo-theme.json @@ -54,6 +54,16 @@ distributing this software or its derivatives. "scrollview": { "overshoot-effect-color":"B018" + }, + + "grouplabel": + { + "point-size":9 + }, + + "buttonlabel": + { + "point-size":11 } } } diff --git a/resources/style/mobile/demo-theme.json b/resources/style/mobile/demo-theme.json index 682db8e..4328b32 100644 --- a/resources/style/mobile/demo-theme.json +++ b/resources/style/mobile/demo-theme.json @@ -94,6 +94,16 @@ distributing this software or its derivatives. "scrollview": { "overshoot-effect-color":"B018" + }, + + "grouplabel": + { + "point-size":6 + }, + + "buttonlabel": + { + "point-size":8 } } } diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index 56adecf..6f408d5 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -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"