[dali_1.1.9] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / image-scaling-and-filtering / image-scaling-and-filtering-example.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <dali/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali-toolkit/devel-api/controls/popup/popup.h>
21 #include "shared/view.h"
22 #include <iostream>
23
24 using namespace Dali;
25 using Toolkit::TextLabel;
26
27 namespace
28 {
29
30 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
31 const Vector4 BACKGROUND_COLOUR( 1.0f, 1.0f, 1.0f, 0.15f );
32
33 const int MARGIN_SIZE = 10;
34
35 const char* const NEXT_BUTTON_ID = "NEXT_BUTTON";
36 const char* const PREVIOUS_BUTTON_ID = "PREVIOUS_BUTTON";
37 const char * const DALI_ICON_PLAY = DALI_IMAGE_DIR "icon-play.png";
38
39 const char* const FITTING_BUTTON_ID = "FITTING_BUTTON";
40 const char* const SAMPLING_BUTTON_ID = "SAMPLING_BUTTON";
41 const char* const FITTING_BUTTON_TEXT = "Fitting";
42 const char* const SAMPLING_BUTTON_TEXT = "Sampling";
43
44 const char* const STYLE_LABEL_TEXT  = "grouplabel";
45 const char* const STYLE_BUTTON_TEXT = "buttonlabel";
46
47
48
49 const char* IMAGE_PATHS[] =
50 {
51   // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered
52   // black and white image:
53   DALI_IMAGE_DIR "gallery-large-14.wbmp",
54   // Variety of sizes, shapes and formats:
55   DALI_IMAGE_DIR "animation-list.png",
56   DALI_IMAGE_DIR "layer1.png",
57   DALI_IMAGE_DIR "layer2.png",
58   DALI_IMAGE_DIR "music-libray-main-screen.png",
59   DALI_IMAGE_DIR "music-libray-record-cover.png",
60   DALI_IMAGE_DIR "contacts-background.png",
61   DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
62   DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
63   DALI_IMAGE_DIR "square_primitive_shapes.bmp",
64   DALI_IMAGE_DIR "dali-logo.png",
65   DALI_IMAGE_DIR "com.samsung.dali-demo.ico",
66   DALI_IMAGE_DIR "gallery-large-14.jpg",
67   DALI_IMAGE_DIR "book-landscape-cover.jpg",
68   DALI_IMAGE_DIR "book-portrait-p1.jpg",
69   DALI_IMAGE_DIR "book-landscape-cover-back.jpg",
70   DALI_IMAGE_DIR "background-1.jpg",
71   DALI_IMAGE_DIR "background-blocks.jpg",
72   DALI_IMAGE_DIR "background-magnifier.jpg",
73   DALI_IMAGE_DIR "gallery-large-14.jpg",
74   NULL
75 };
76 const int NUM_IMAGE_PATHS = sizeof(IMAGE_PATHS) / sizeof(IMAGE_PATHS[0]) - 1u;
77
78 /** Cycle the scaling mode options. */
79 FittingMode::Type NextScalingMode( FittingMode::Type oldMode )
80 {
81   FittingMode::Type newMode = FittingMode::SHRINK_TO_FIT;
82   switch ( oldMode )
83   {
84     case FittingMode::SHRINK_TO_FIT:
85       newMode = FittingMode::SCALE_TO_FILL;
86       break;
87     case FittingMode::SCALE_TO_FILL:
88       newMode = FittingMode::FIT_WIDTH;
89       break;
90     case FittingMode::FIT_WIDTH:
91       newMode = FittingMode::FIT_HEIGHT;
92       break;
93     case FittingMode::FIT_HEIGHT:
94       newMode = FittingMode::SHRINK_TO_FIT;
95       break;
96   }
97   return newMode;
98 }
99
100 /** Cycle through filter mode options. */
101 SamplingMode::Type NextFilterMode( SamplingMode::Type oldMode )
102 {
103   SamplingMode::Type newMode = SamplingMode::BOX;
104
105   switch ( oldMode )
106   {
107     case SamplingMode::BOX:
108       newMode = SamplingMode::NEAREST;
109       break;
110     case SamplingMode::NEAREST:
111       newMode = SamplingMode::LINEAR;
112       break;
113     case SamplingMode::LINEAR:
114       newMode = SamplingMode::BOX_THEN_NEAREST;
115       break;
116     case SamplingMode::BOX_THEN_NEAREST:
117       newMode = SamplingMode::BOX_THEN_LINEAR;
118       break;
119     case SamplingMode::BOX_THEN_LINEAR:
120       newMode = SamplingMode::NO_FILTER;
121       break;
122     case SamplingMode::NO_FILTER:
123       newMode = SamplingMode::BOX;
124       break;
125     case SamplingMode::DONT_CARE:
126       newMode = SamplingMode::BOX;
127       break;
128   }
129   return newMode;
130 }
131
132 const char* StringFromScalingMode( FittingMode::Type scalingMode )
133 {
134   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";
135 }
136
137 const char* StringFromFilterMode( SamplingMode::Type filterMode )
138 {
139   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";
140 }
141
142 }
143
144 // This example shows the load-time image scaling and filtering features.
145 //
146 class ImageScalingAndFilteringController : public ConnectionTracker
147 {
148 public:
149
150   ImageScalingAndFilteringController( Application& application )
151   : mApplication( application ),
152     mImageStageScale( 0.5f, 0.5f ),
153     mCurrentPath( 0 ),
154     mFittingMode( FittingMode::SCALE_TO_FILL ),
155     mSamplingMode( SamplingMode::BOX_THEN_LINEAR)
156   {
157     // Connect to the Application's Init signal
158     mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create );
159   }
160
161   ~ImageScalingAndFilteringController()
162   {
163     // Nothing to do here;
164   }
165
166   // The Init signal is received once (only) during the Application lifetime
167   void Create( Application& application )
168   {
169     // Get a handle to the stage
170     Stage stage = Stage::GetCurrent();
171
172     // Background image:
173     Dali::Property::Map backgroundImage;
174     backgroundImage.Insert( "rendererType",  "imageRenderer" );
175     backgroundImage.Insert( "imageUrl",  BACKGROUND_IMAGE );
176     backgroundImage.Insert( "imageDesiredWidth",   stage.GetSize().width );
177     backgroundImage.Insert( "imageDesiredHeight",   stage.GetSize().height );
178     backgroundImage.Insert( "imageFittingMode",   "scaleToFill" );
179     backgroundImage.Insert( "imageSamplingMode",   "boxThenNearest" );
180
181     Toolkit::ImageView background = Toolkit::ImageView::New();
182     background.SetProperty( Toolkit::ImageView::Property::IMAGE, backgroundImage );
183     background.SetAnchorPoint( AnchorPoint::TOP_LEFT );
184     background.SetSize( stage.GetSize() );
185     stage.Add( background );
186
187     // Make grey pixels for the desired box, the desired height the desired width:
188     BufferImage desiredBackground = BufferImage::WHITE();
189
190     BufferImage heightBackground = BufferImage::WHITE();
191     PixelBuffer* const heightPixel = heightBackground.GetBuffer();
192     heightPixel[0] = 0x8f;
193     heightPixel[1] = 0x8f;
194     heightPixel[2] = 0x8f;
195
196     BufferImage widthBackground = BufferImage::WHITE();
197     PixelBuffer* const widthPixel = widthBackground.GetBuffer();
198     widthPixel[0] = 0x4f;
199     widthPixel[1] = 0x4f;
200     widthPixel[2] = 0x4f;
201
202     mHeightBox = Toolkit::ImageView::New( heightBackground );
203     mHeightBox.SetOpacity( 0.2f );
204     background.Add( mHeightBox );
205
206     mWidthBox = Toolkit::ImageView::New( widthBackground );
207     mWidthBox.SetOpacity( 0.2f );
208     background.Add( mWidthBox );
209
210     mDesiredBox = Toolkit::ImageView::New( desiredBackground );
211     background.Add( mDesiredBox );
212
213     mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
214     mDesiredBox.SetParentOrigin( ParentOrigin::CENTER );
215     mDesiredBox.SetAnchorPoint( AnchorPoint::CENTER );
216
217     mHeightBox.SetSize( stage.GetSize().width,  (stage.GetSize() * mImageStageScale).height );
218     mHeightBox.SetParentOrigin( ParentOrigin::CENTER );
219     mHeightBox.SetAnchorPoint( AnchorPoint::CENTER );
220
221     mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
222     mWidthBox.SetParentOrigin( ParentOrigin::CENTER );
223     mWidthBox.SetAnchorPoint( AnchorPoint::CENTER );
224
225     // Initialize the actor
226     mImageView = Toolkit::ImageView::New( IMAGE_PATHS[ 0 ] );
227
228     // Reposition the actor
229     mImageView.SetParentOrigin( ParentOrigin::CENTER );
230     mImageView.SetAnchorPoint( AnchorPoint::CENTER );
231
232     // Display the actor on the stage
233     mDesiredBox.Add( mImageView );
234
235     mImageView.SetSize( stage.GetSize() * mImageStageScale );
236
237     // Setup the pinch detector for scaling the desired image load dimensions:
238     mPinchDetector = PinchGestureDetector::New();
239     mPinchDetector.Attach( mImageView );
240     mPinchDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPinch );
241
242     // Make a grab-handle for resizing the image:
243     mGrabCorner = Toolkit::PushButton::New();
244     mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
245     mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
246     mGrabCorner.SetName( "GrabCorner" );
247     mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
248     mGrabCorner.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
249     mGrabCorner.SetSize( Vector2( stage.GetSize().width*0.08f, stage.GetSize().width*0.08f ) );
250     mGrabCorner.SetOpacity( 0.6f );
251
252     Layer grabCornerLayer = Layer::New();
253     grabCornerLayer.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
254     grabCornerLayer.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
255
256     grabCornerLayer.Add( mGrabCorner );
257     mImageView.Add( grabCornerLayer );
258     mPanGestureDetector = PanGestureDetector::New();
259     mPanGestureDetector.Attach( mGrabCorner );
260     mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan );
261
262
263     // Tie-in input event handlers:
264     stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent );
265
266     CreateControls();
267
268     ResizeImage();
269   }
270
271   /**
272    * Create the GUI controls which float above the scene
273    */
274   void CreateControls()
275   {
276     Stage stage = Stage::GetCurrent();
277
278     Dali::Layer controlsLayer = Dali::Layer::New();
279     controlsLayer.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
280     controlsLayer.SetSizeModeFactor( Vector3( 1.0f, 1.0f, 1.0f ) );
281     controlsLayer.SetAnchorPoint( AnchorPoint::TOP_LEFT);
282     controlsLayer.SetParentOrigin( ParentOrigin::TOP_LEFT);
283     stage.Add( controlsLayer );
284
285     // Back and next image buttons in corners of stage:
286     unsigned int playWidth = std::min( stage.GetSize().x * (1 / 5.0f), 58.0f );
287     Image playImage = ResourceImage::New( DALI_ICON_PLAY, ImageDimensions( playWidth, playWidth ), FittingMode::SHRINK_TO_FIT, SamplingMode::BOX_THEN_LINEAR );
288     Toolkit::ImageView imagePrevious = Toolkit::ImageView::New( playImage );
289
290     // Last image button:
291     imagePrevious.SetAnchorPoint( AnchorPoint::TOP_LEFT );
292     imagePrevious.RotateBy( Radian(3.14159265358979323846f), Vector3( 0, 1.0f, 0 ) );
293     imagePrevious.SetY( playWidth * 0.5f );
294     imagePrevious.SetX( playWidth + playWidth * 0.5f );
295     imagePrevious.SetOpacity( 0.6f );
296     controlsLayer.Add( imagePrevious );
297     imagePrevious.SetName( PREVIOUS_BUTTON_ID );
298     imagePrevious.TouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnControlTouched );
299
300     // Next image button:
301     Toolkit::ImageView imageNext = Toolkit::ImageView::New( playImage );
302     imageNext.SetAnchorPoint( AnchorPoint::TOP_RIGHT );
303     imageNext.SetY( playWidth * 0.5f );
304     imageNext.SetX( stage.GetSize().x - playWidth * 0.5f );
305     imageNext.SetOpacity( 0.6f );
306     controlsLayer.Add( imageNext );
307     imageNext.SetName( NEXT_BUTTON_ID );
308     imageNext.TouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnControlTouched );
309
310     // Buttons to popup selectors for fitting and sampling modes:
311
312     // Wrapper table to hold two buttons side by side:
313     Toolkit::TableView modesGroupBackground = Toolkit::TableView::New( 1, 2 );
314     modesGroupBackground.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
315     modesGroupBackground.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
316     modesGroupBackground.SetBackgroundColor( BACKGROUND_COLOUR );
317     modesGroupBackground.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE ) );
318     modesGroupBackground.SetFitHeight( 0 );
319
320     modesGroupBackground.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
321     modesGroupBackground.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
322     modesGroupBackground.SetPosition( 0.0f, 0.0f );
323
324     controlsLayer.Add( modesGroupBackground );
325
326     {
327       // Vertical table to hold label and button:
328       Toolkit::TableView fittingModeGroup = Toolkit::TableView::New( 2, 1 );
329       fittingModeGroup.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
330       fittingModeGroup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
331       fittingModeGroup.SetBackgroundColor( BACKGROUND_COLOUR );
332       fittingModeGroup.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE * 0.5f ) );
333       fittingModeGroup.SetFitHeight( 0 );
334       fittingModeGroup.SetFitHeight( 1 );
335
336       TextLabel label = TextLabel::New( "Image fitting mode:" );
337       label.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_LABEL_TEXT );
338       fittingModeGroup.Add( label );
339
340       Toolkit::PushButton button = CreateButton( FITTING_BUTTON_ID, StringFromScalingMode( mFittingMode ) );
341       fittingModeGroup.Add( button );
342       mFittingModeButton = button;
343
344       modesGroupBackground.Add( fittingModeGroup );
345     }
346
347     {
348       // Vertical table to hold label and button:
349       Toolkit::TableView samplingModeGroup = Toolkit::TableView::New( 2, 1 );
350       samplingModeGroup.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
351       samplingModeGroup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
352       samplingModeGroup.SetBackgroundColor( BACKGROUND_COLOUR );
353       samplingModeGroup.SetCellPadding( Size( MARGIN_SIZE * 0.5f, MARGIN_SIZE * 0.5f ) );
354       samplingModeGroup.SetFitHeight( 0 );
355       samplingModeGroup.SetFitHeight( 1 );
356
357       TextLabel label = TextLabel::New( "Image sampling mode:" );
358       label.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_LABEL_TEXT );
359       samplingModeGroup.Add( label );
360
361       Toolkit::PushButton button = CreateButton( SAMPLING_BUTTON_ID, StringFromFilterMode( mSamplingMode ) );
362       samplingModeGroup.Add( button );
363       mSamplingModeButton = button;
364
365       modesGroupBackground.Add( samplingModeGroup );
366     }
367   }
368
369   Toolkit::PushButton CreateButton( const char * id, const char * label )
370   {
371     Toolkit::PushButton button = Toolkit::PushButton::New();
372     button.SetProperty( Toolkit::Control::Property::STYLE_NAME, STYLE_BUTTON_TEXT );
373     button.SetName( id );
374     button.SetLabelText( label );
375     button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
376     button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
377     button.ClickedSignal().Connect( this, &ImageScalingAndFilteringController::OnButtonClicked );
378     return button;
379   }
380
381   Toolkit::Popup CreatePopup()
382   {
383     Stage stage = Stage::GetCurrent();
384     const float POPUP_WIDTH_DP = stage.GetSize().width * 0.75f;
385
386     Toolkit::Popup popup = Toolkit::Popup::New();
387     popup.SetName( "POPUP" );
388     popup.SetParentOrigin( ParentOrigin::CENTER );
389     popup.SetAnchorPoint( AnchorPoint::CENTER );
390     popup.SetSize( POPUP_WIDTH_DP, 0.0f );
391
392     popup.OutsideTouchedSignal().Connect( this, &ImageScalingAndFilteringController::OnPopupOutsideTouched );
393
394     return popup;
395   }
396
397   //void CreatePopupButton( Toolkit::Popup popup, const char* id )
398   Toolkit::PushButton CreatePopupButton( Actor parent, const char* id )
399   {
400     Toolkit::PushButton button = Toolkit::PushButton::New();
401     button.SetName( id );
402     button.SetLabelText( id );
403
404     button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
405     button.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
406     button.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
407     button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
408
409     button.ClickedSignal().Connect( this, &ImageScalingAndFilteringController::OnButtonClicked );
410
411     parent.Add( button );
412     return button;
413   }
414
415   bool OnButtonClicked( Toolkit::Button button )
416   {
417     if( button.GetName() == FITTING_BUTTON_ID )
418     {
419       mPopup = CreatePopup();
420
421       // Four-row table to hold buttons:
422       Toolkit::TableView fittingModes = Toolkit::TableView::New( 4, 1 );
423       fittingModes.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
424       fittingModes.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
425       fittingModes.SetCellPadding( Size( MARGIN_SIZE, MARGIN_SIZE * 0.5 ) );
426       fittingModes.SetFitHeight( 0 );
427       fittingModes.SetFitHeight( 1 );
428       fittingModes.SetFitHeight( 2 );
429       fittingModes.SetFitHeight( 3 );
430
431       CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::SCALE_TO_FILL ) );
432       CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::SHRINK_TO_FIT ) );
433       CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::FIT_WIDTH ) );
434       CreatePopupButton( fittingModes, StringFromScalingMode( FittingMode::FIT_HEIGHT ) );
435
436       mPopup.SetContent( fittingModes );
437       Stage::GetCurrent().Add( mPopup );
438       mPopup.SetDisplayState( Toolkit::Popup::SHOWN );
439     }
440     else if( button.GetName() == SAMPLING_BUTTON_ID )
441     {
442       mPopup = CreatePopup();
443
444       // Table to hold buttons for each sampling mode:
445       Toolkit::TableView samplingModes = Toolkit::TableView::New( 6, 1 );
446       samplingModes.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
447       samplingModes.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
448       samplingModes.SetCellPadding( Size( MARGIN_SIZE, MARGIN_SIZE * 0.5 ) );
449       samplingModes.SetFitHeight( 0 );
450       samplingModes.SetFitHeight( 1 );
451       samplingModes.SetFitHeight( 2 );
452       samplingModes.SetFitHeight( 3 );
453       samplingModes.SetFitHeight( 4 );
454       samplingModes.SetFitHeight( 5 );
455
456       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::NEAREST ) );
457       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::LINEAR ) );
458       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX ) );
459       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX_THEN_NEAREST ) );
460       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::BOX_THEN_LINEAR ) );
461       CreatePopupButton( samplingModes, StringFromFilterMode( SamplingMode::NO_FILTER ) );
462
463       mPopup.SetContent( samplingModes );
464       Stage::GetCurrent().Add( mPopup );
465       mPopup.SetDisplayState( Toolkit::Popup::SHOWN );
466     }
467     else if( CheckFittingModeButton( button, FittingMode::SCALE_TO_FILL) ||
468              CheckFittingModeButton( button, FittingMode::SHRINK_TO_FIT) ||
469              CheckFittingModeButton( button, FittingMode::FIT_WIDTH) ||
470              CheckFittingModeButton( button, FittingMode::FIT_HEIGHT) )
471     {
472     }
473     else if( CheckSamplingModeButton( button, SamplingMode::NEAREST ) ||
474              CheckSamplingModeButton( button, SamplingMode::LINEAR ) ||
475              CheckSamplingModeButton( button, SamplingMode::BOX ) ||
476              CheckSamplingModeButton( button, SamplingMode::LINEAR ) ||
477              CheckSamplingModeButton( button, SamplingMode::BOX_THEN_NEAREST ) ||
478              CheckSamplingModeButton( button, SamplingMode::BOX_THEN_LINEAR ) ||
479              CheckSamplingModeButton( button, SamplingMode::NO_FILTER ) )
480     {
481     }
482     return true;
483   }
484
485   bool CheckFittingModeButton( Actor &button, FittingMode::Type mode )
486   {
487     const char * const modeName = StringFromScalingMode( mode );
488     if( button.GetName() == modeName )
489     {
490       mFittingMode = mode;
491       mFittingModeButton.SetLabelText( modeName );
492       ResizeImage();
493       mPopup.SetDisplayState( Toolkit::Popup::HIDDEN );
494       mPopup.Reset();
495       return true;
496     }
497     return false;
498   }
499
500   bool CheckSamplingModeButton( Actor &button, SamplingMode::Type mode )
501   {
502     const char * const modeName = StringFromFilterMode( mode );
503     if( button.GetName() == modeName )
504     {
505       mSamplingMode = mode;
506       mSamplingModeButton.SetLabelText( modeName );
507       ResizeImage();
508       mPopup.SetDisplayState( Toolkit::Popup::HIDDEN );
509       mPopup.Reset();
510       return true;
511     }
512     return false;
513   }
514
515   void OnPopupOutsideTouched()
516   {
517     if( mPopup )
518     {
519       mPopup.SetDisplayState( Toolkit::Popup::HIDDEN );
520       mPopup.Reset();
521     }
522   }
523
524   void OnImageLoaded( ResourceImage image )
525   {
526       DALI_ASSERT_DEBUG( image == mNextImage );
527       mImageView.SetImage( image );
528       mImageView.SetSize( Size( image.GetWidth(), image.GetHeight() ) );
529   }
530
531   bool OnControlTouched( Actor actor, const TouchEvent& event )
532   {
533     if(event.GetPointCount() > 0)
534     {
535       const TouchPoint& point = event.GetPoint(0);
536       switch(point.state)
537       {
538         case TouchPoint::Up:
539         {
540           const std::string & name = actor.GetName();
541           if( name == NEXT_BUTTON_ID )
542           {
543             mCurrentPath = mCurrentPath + 1;
544             mCurrentPath = mCurrentPath <  NUM_IMAGE_PATHS ? mCurrentPath : 0;
545             ResizeImage();
546           }
547           else if( name == PREVIOUS_BUTTON_ID )
548           {
549             mCurrentPath = mCurrentPath - 1;
550             mCurrentPath = mCurrentPath >= 0 ? mCurrentPath : NUM_IMAGE_PATHS - 1;
551             ResizeImage();
552           }
553           break;
554         }
555         default:
556         {
557           break;
558         }
559       } // end switch
560     }
561
562     return false;
563   }
564
565   void OnPinch( Actor actor, const PinchGesture& pinch )
566   {
567     if( pinch.state == Gesture::Started )
568     {
569       mLastPinchScale = pinch.scale;
570     }
571     const float scale = pinch.scale;
572
573     if( scale != mLastPinchScale )
574     {
575       if ( scale < mLastPinchScale )
576       {
577         mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
578         mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
579       }
580       else
581       {
582         mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
583         mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
584       }
585       ResizeImage();
586     }
587     mLastPinchScale = scale;
588   }
589
590   void OnPan( Actor actor, const PanGesture& gesture )
591   {
592     Stage stage = Stage::GetCurrent();
593     mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x + (gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );
594     mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y + (gesture.displacement.y * 2.0f / stage.GetSize().height ) ) );
595     ResizeImage();
596   }
597
598   void OnKeyEvent(const KeyEvent& event)
599   {
600     if( event.state == KeyEvent::Down )
601     {
602       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
603       {
604         if( mPopup && mPopup.IsVisible() )
605         {
606           mPopup.SetDisplayState( Toolkit::Popup::HIDDEN );
607           mPopup.Reset();
608         }
609         else
610         {
611           mApplication.Quit();
612         }
613       }
614       else if ( event.keyPressedName == "Right" )
615       {
616         mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
617       }
618       else if ( event.keyPressedName == "Left" )
619       {
620         mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
621       }
622       else if ( event.keyPressedName == "Up" )
623       {
624         mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
625       }
626       else if ( event.keyPressedName == "Down" )
627       {
628         mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
629       }
630       else if ( event.keyPressedName == "o" )
631       {
632         mImageStageScale.x = std::max( 0.05f, mImageStageScale.x * 0.9f );
633         mImageStageScale.y = std::max( 0.05f, mImageStageScale.y * 0.9f );
634       }
635       else if ( event.keyPressedName == "p" )
636       {
637         mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x * 1.1f ) );
638         mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y * 1.1f ) );
639       }
640       else if ( event.keyPressedName == "n" )
641       {
642         mCurrentPath = mCurrentPath + 1;
643         mCurrentPath = mCurrentPath <  NUM_IMAGE_PATHS ? mCurrentPath : 0;
644       }
645       else if ( event.keyPressedName == "b" )
646       {
647         mCurrentPath = mCurrentPath - 1;
648         mCurrentPath = mCurrentPath >= 0 ? mCurrentPath : NUM_IMAGE_PATHS - 1;
649       }
650       // Cycle filter and scaling modes:
651       else if ( event.keyPressedName == "f" )
652       {
653         mSamplingMode = NextFilterMode( mSamplingMode );
654         mSamplingModeButton.SetLabelText( StringFromFilterMode( mSamplingMode ) );
655       }
656       // Cycle filter and scaling modes:
657       else if ( event.keyPressedName == "s" )
658       {
659         mFittingMode = NextScalingMode( mFittingMode );
660         mFittingModeButton.SetLabelText( StringFromScalingMode( mFittingMode ) );
661       }
662       else
663       {
664         return;
665       }
666
667       ResizeImage();
668     }
669   }
670
671 private:
672   void ResizeImage()
673   {
674     const char * const path = IMAGE_PATHS[mCurrentPath];
675
676     Stage stage = Stage::GetCurrent();
677     Size imageSize = stage.GetSize() * mImageStageScale;
678     const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x );
679
680     ResourceImage image = ResourceImage::New( path, imageSizeInt, mFittingMode, mSamplingMode );
681     image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded );
682
683     mNextImage = image;
684
685     mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
686     mHeightBox.SetSize( stage.GetSize().width,  (stage.GetSize() * mImageStageScale).height );
687     mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
688   }
689
690 private:
691   Application&  mApplication;
692   Toolkit::ImageView mDesiredBox; //< Background rectangle to show requested image size.
693   Toolkit::ImageView mHeightBox;  //< Background horizontal stripe to show requested image height.
694   Toolkit::ImageView mWidthBox;   //< Background vertical stripe to show requested image width.
695   Toolkit::PushButton mFittingModeButton;
696   Toolkit::PushButton mSamplingModeButton;
697   Toolkit::Popup mPopup;
698   PinchGestureDetector mPinchDetector;
699   float mLastPinchScale;
700   Toolkit::PushButton  mGrabCorner;
701   PanGestureDetector mPanGestureDetector;
702   Toolkit::ImageView mImageView;
703   ResourceImage mNextImage; //< Currently-loading image
704   Vector2 mImageStageScale;
705   int mCurrentPath;
706   FittingMode::Type mFittingMode;
707   SamplingMode::Type mSamplingMode;
708 };
709
710 void RunTest( Application& application )
711 {
712   ImageScalingAndFilteringController test( application );
713
714   application.MainLoop();
715 }
716
717 // Entry point for Linux & Tizen applications
718 int main( int argc, char **argv )
719 {
720   Application application = Application::New( &argc, &argv, DALI_DEMO_THEME_PATH );
721
722   RunTest( application );
723
724   return 0;
725 }