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