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