Merge "Modify RadioButton test case" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / push-button-impl.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 // CLASS HEADER
19 #include "push-button-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/image-actor.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/devel-api/object/type-registry-helper.h>
25 #include <dali/public-api/images/resource-image.h>
26 #include <dali/devel-api/scripting/scripting.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
30
31 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Internal
38 {
39
40 namespace
41 {
42
43 const float   ANIMATION_TIME( 0.2f );
44 const Padding DEFAULT_LABEL_PADDING( 12.0f, 12.0f, 12.0f, 12.0f );
45 const Padding DEFAULT_ICON_PADDING( 12.0f, 12.0f, 12.0f, 12.0f );
46
47 BaseHandle Create()
48 {
49   return Toolkit::PushButton::New();
50 }
51
52 // Properties
53
54 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::PushButton, Toolkit::Button, Create )
55
56 DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "unselected-icon", STRING, UNSELECTED_ICON )
57 DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "selected-icon", STRING, SELECTED_ICON )
58 DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "icon-alignment", STRING, ICON_ALIGNMENT )
59 DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "label-padding", STRING, LABEL_PADDING )
60 DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "icon-padding", STRING, ICON_PADDING )
61
62 DALI_TYPE_REGISTRATION_END()
63
64 /*
65  * Table to define Text-to-enum conversions for IconAlignment.
66  */
67 const Dali::Scripting::StringEnum IconAlignmentTable[] = {
68   { "LEFT",   Toolkit::Internal::PushButton::LEFT },
69   { "RIGHT",  Toolkit::Internal::PushButton::RIGHT },
70   { "TOP",    Toolkit::Internal::PushButton::TOP },
71   { "BOTTOM", Toolkit::Internal::PushButton::BOTTOM },
72 }; const unsigned int IconAlignmentTableCount = sizeof( IconAlignmentTable ) / sizeof( IconAlignmentTable[0] );
73
74 const char* const UNSELECTED_BUTTON_IMAGE_DIR = DALI_IMAGE_DIR "button-up.9.png";
75 const char* const SELECTED_BUTTON_IMAGE_DIR = DALI_IMAGE_DIR "button-down.9.png";
76 const char* const DISABLED_UNSELECTED_BUTTON_IMAGE_DIR = DALI_IMAGE_DIR "button-disabled.9.png";
77 const char* const DISABLED_SELECTED_BUTTON_IMAGE_DIR = DALI_IMAGE_DIR "button-down-disabled.9.png";
78
79 } // unnamed namespace
80
81 namespace
82 {
83
84 /**
85  * Get size of Actor if larger than given size
86  * @param[in] root the actor to get the size of
87  * @param[out] size the greater of the given size or the size of the Actor
88  */
89 void SizeOfActorIfLarger( Actor root, Vector3& size )
90 {
91   if ( root )
92   {
93     // RelayoutSize retreived for Actor to use any padding set to it.
94     size.width = std::max( root.GetRelayoutSize( Dimension::WIDTH ), size.width );
95     size.height = std::max( root.GetRelayoutSize( Dimension::HEIGHT ), size.height );
96   }
97 }
98
99 } // unnamed namespace
100
101 Dali::Toolkit::PushButton PushButton::New()
102 {
103   // Create the implementation, temporarily owned on stack
104   IntrusivePtr< PushButton > internalPushButton = new PushButton();
105
106   // Pass ownership to CustomActor
107   Dali::Toolkit::PushButton pushButton( *internalPushButton );
108
109   // Second-phase init of the implementation
110   // This can only be done after the CustomActor connection has been made...
111   internalPushButton->Initialize();
112
113   return pushButton;
114 }
115
116 PushButton::PushButton()
117 : Button(),
118   mLabelPadding( DEFAULT_LABEL_PADDING ),
119   mIconPadding( DEFAULT_ICON_PADDING ),
120   mIconAlignment( RIGHT ),
121   mSize()
122 {
123   SetAnimationTime( ANIMATION_TIME );
124 }
125
126 PushButton::~PushButton()
127 {
128 }
129
130 void PushButton::OnButtonInitialize()
131 {
132   // Push button requires the Leave event.
133   Actor self = Self();
134   self.SetLeaveRequired( true );
135
136   // Set resize policy to natural size so that buttons will resize to background images
137   self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
138
139   SetUnselectedImage( UNSELECTED_BUTTON_IMAGE_DIR );
140   SetSelectedImage( SELECTED_BUTTON_IMAGE_DIR );
141   SetDisabledImage( DISABLED_UNSELECTED_BUTTON_IMAGE_DIR );
142   SetDisabledSelectedImage( DISABLED_SELECTED_BUTTON_IMAGE_DIR );
143 }
144
145 void PushButton::SetIcon( DecorationState state, const std::string iconFilename )
146 {
147   mIconName[ state ] = iconFilename;
148   SetDecoration( state, ImageActor::New( Dali::ResourceImage::New( iconFilename ) ) );
149   ConfigureSizeNegotiation();
150 }
151
152 std::string& PushButton::GetIcon( DecorationState state )
153 {
154   return mIconName[ state ];
155 }
156
157 void PushButton::SetIconAlignment( const PushButton::IconAlignment iconAlignment )
158 {
159   mIconAlignment = iconAlignment;
160   ConfigureSizeNegotiation();
161 }
162
163 const PushButton::IconAlignment PushButton::GetIconAlignment() const
164 {
165   return mIconAlignment;
166 }
167
168 void PushButton::SetLabelPadding( const Vector4& padding )
169 {
170   mLabelPadding = Padding( padding.x, padding.y, padding.z, padding.w );
171   ConfigureSizeNegotiation();
172 }
173
174 Vector4 PushButton::GetLabelPadding()
175 {
176   return Vector4( mLabelPadding.left, mLabelPadding.right, mLabelPadding.top, mLabelPadding.bottom );
177 }
178
179 void PushButton::SetIconPadding( const Vector4& padding )
180 {
181   mIconPadding = Padding( padding.x, padding.y, padding.z, padding.w );
182   ConfigureSizeNegotiation();
183 }
184
185 Vector4 PushButton::GetIconPadding()
186 {
187   return Vector4( mIconPadding.left, mIconPadding.right, mIconPadding.top, mIconPadding.bottom );
188 }
189
190 void PushButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
191 {
192   Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
193
194   if ( pushButton )
195   {
196     PushButton& pushButtonImpl( GetImplementation( pushButton ) );
197
198     switch ( propertyIndex )
199     {
200       case Toolkit::PushButton::Property::UNSELECTED_ICON:
201       {
202         pushButtonImpl.SetIcon( UNSELECTED_DECORATION, value.Get< std::string >() );
203         break;
204       }
205       case Toolkit::PushButton::Property::SELECTED_ICON:
206       {
207         pushButtonImpl.SetIcon( SELECTED_DECORATION, value.Get< std::string >() );
208         break;
209       }
210       case Toolkit::PushButton::Property::ICON_ALIGNMENT:
211       {
212         IconAlignment iconAlignment;
213         if( Scripting::GetEnumeration< IconAlignment >( value.Get< std::string >().c_str(), IconAlignmentTable, IconAlignmentTableCount, iconAlignment ) )
214         {
215           pushButtonImpl.SetIconAlignment( iconAlignment );
216         }
217         break;
218       }
219       case Toolkit::PushButton::Property::LABEL_PADDING:
220       {
221         pushButtonImpl.SetLabelPadding( value.Get< Vector4 >() );
222         break;
223       }
224       case Toolkit::PushButton::Property::ICON_PADDING:
225       {
226         pushButtonImpl.SetIconPadding( value.Get< Vector4 >() );
227         break;
228       }
229     }
230   }
231 }
232
233 Property::Value PushButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
234 {
235   Property::Value value;
236
237   Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
238
239   if ( pushButton )
240   {
241     PushButton& pushButtonImpl( GetImplementation( pushButton ) );
242
243     switch ( propertyIndex )
244     {
245       case Toolkit::PushButton::Property::UNSELECTED_ICON:
246       {
247         value = pushButtonImpl.GetIcon( UNSELECTED_DECORATION );
248         break;
249       }
250       case Toolkit::PushButton::Property::SELECTED_ICON:
251       {
252         value = pushButtonImpl.GetIcon( UNSELECTED_DECORATION );
253         break;
254       }
255       case Toolkit::PushButton::Property::ICON_ALIGNMENT:
256       {
257         value = Scripting::GetLinearEnumerationName< IconAlignment >( pushButtonImpl.GetIconAlignment(), IconAlignmentTable, IconAlignmentTableCount );
258         break;
259       }
260       case Toolkit::PushButton::Property::LABEL_PADDING:
261       {
262         value = pushButtonImpl.GetLabelPadding();
263         break;
264       }
265       case Toolkit::PushButton::Property::ICON_PADDING:
266       {
267         value = pushButtonImpl.GetIconPadding();
268         break;
269       }
270     }
271   }
272
273   return value;
274 }
275
276 void PushButton::OnLabelSet()
277 {
278   Actor& label = GetLabelActor();
279
280   if( label )
281   {
282     Toolkit::TextLabel textLabel = Toolkit::TextLabel::DownCast( label );
283     if( textLabel )
284     {
285       textLabel.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, false );
286     }
287   }
288   ConfigureSizeNegotiation();
289 }
290
291 void PushButton::OnButtonImageSet()
292 {
293   ConfigureSizeNegotiation();
294 }
295
296 void PushButton::OnSelectedImageSet()
297 {
298   ConfigureSizeNegotiation();
299 }
300
301 void PushButton::OnBackgroundImageSet()
302 {
303   ConfigureSizeNegotiation();
304 }
305
306 void PushButton::OnSelectedBackgroundImageSet()
307 {
308   ConfigureSizeNegotiation();
309 }
310
311 void PushButton::OnDisabledImageSet()
312 {
313   ConfigureSizeNegotiation();
314 }
315
316 void PushButton::OnDisabledSelectedImageSet()
317 {
318   ConfigureSizeNegotiation();
319 }
320
321 void PushButton::OnDisabledBackgroundImageSet()
322 {
323   ConfigureSizeNegotiation();
324 }
325
326 void PushButton::OnSizeSet( const Vector3& targetSize )
327 {
328   if( targetSize != mSize )
329   {
330     mSize = targetSize;
331
332     Actor& label = GetLabelActor();
333
334     if( label )
335     {
336       label.SetSize( mSize );
337     }
338   }
339 }
340
341 void PushButton::PrepareForTranstionIn( Actor actor )
342 {
343   actor.SetOpacity( 0.0f );
344 }
345
346 void PushButton::PrepareForTranstionOut( Actor actor )
347 {
348   actor.SetOpacity( 1.0f );
349 }
350
351 void PushButton::OnTransitionIn( Actor actor )
352 {
353   FadeImageTo( actor, 1.f );
354 }
355
356 void PushButton::OnTransitionOut( Actor actor )
357 {
358   FadeImageTo( actor, 0.0f );
359 }
360
361 void PushButton::FadeImageTo( Actor actor, float opacity )
362 {
363   if( actor )
364   {
365     Dali::Animation transitionAnimation = GetTransitionAnimation();
366     DALI_ASSERT_DEBUG( transitionAnimation );
367
368     if( transitionAnimation )
369     {
370       transitionAnimation.AnimateTo( Property( actor, Actor::Property::COLOR_ALPHA ), opacity );
371     }
372   }
373 }
374
375 Vector3 PushButton::GetNaturalSize()
376 {
377   Vector3 size;
378
379   // If label, test against it's size
380   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( GetLabelActor() );
381
382   Actor icon = GetDecoration( UNSELECTED_DECORATION );
383   if( label || icon )
384   {
385     Vector3 labelSize( Vector3::ZERO );
386     Vector3 iconSize( Vector3::ZERO );
387
388     if( label )
389     {
390       Vector3 labelNaturalSize = label.GetNaturalSize();
391       labelSize.width = labelNaturalSize.width + mLabelPadding.left + mLabelPadding.right;
392       labelSize.height = labelNaturalSize.height + mLabelPadding.top + mLabelPadding.bottom;
393     }
394
395     if( icon )
396     {
397       Vector3 iconNaturalSize = icon.GetNaturalSize();
398       iconSize.width = iconNaturalSize.width + mIconPadding.left + mIconPadding.right;
399       iconSize.height = iconNaturalSize.height + mIconPadding.top + mIconPadding.bottom;
400
401       switch( mIconAlignment )
402       {
403         case LEFT:
404         case RIGHT:
405         {
406           size.width = labelSize.width + iconSize.width;
407           size.height = std::max( labelSize.height, iconSize.height );
408           break;
409         }
410         case TOP:
411         case BOTTOM:
412         {
413           size.width = std::max( labelSize.width, iconSize.width );
414           size.height = labelSize.height + iconSize.height;
415           break;
416         }
417       }
418     }
419     else
420     {
421       // No icon, so size is the same as label size.
422       // (If there is no label this is zero).
423       size = labelSize;
424     }
425   }
426   else
427   {
428     // Check Image and Background image and use the largest size as the control's Natural size.
429     SizeOfActorIfLarger( GetUnselectedImage(), size );
430     SizeOfActorIfLarger( GetBackgroundImage(), size );
431   }
432
433   return size;
434 }
435
436 void PushButton::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
437 {
438   ConfigureSizeNegotiation();
439 }
440
441 void PushButton::ConfigureSizeNegotiation()
442 {
443   std::vector< Actor > images;
444   images.reserve( 7 );
445
446   images.push_back( GetUnselectedImage() );
447   images.push_back( GetSelectedImage() );
448   images.push_back( GetSelectedBackgroundImage() );
449   images.push_back( GetBackgroundImage() );
450   images.push_back( GetDisabledImage() );
451   images.push_back( GetDisabledSelectedImage() );
452   images.push_back( GetDisabledBackgroundImage() );
453
454   Actor label = GetLabelActor();
455
456   for( unsigned int i = 0; i < Dimension::DIMENSION_COUNT; ++i )
457   {
458     ConfigureSizeNegotiationDimension( static_cast< Dimension::Type >( 1 << i ), images, label );
459   }
460
461   // Add any vertical padding directly to the actors.
462   Actor icon = GetDecoration( UNSELECTED_DECORATION );
463   Actor selectedIcon = GetDecoration( SELECTED_DECORATION );
464   bool iconExists = icon || selectedIcon;
465
466   if( label )
467   {
468     label.SetPadding( mLabelPadding );
469   }
470   if( icon )
471   {
472     icon.SetPadding( mIconPadding );
473   }
474   if( selectedIcon )
475   {
476     selectedIcon.SetPadding( mIconPadding );
477   }
478
479   // Calculate and apply horizontal alignments and offsets
480   // to text and icon (depending on existence).
481   Vector3 iconPosition( Vector3::ZERO );
482   Vector3 labelPosition( Vector3::ZERO );
483   Vector3 iconAnchoring( AnchorPoint::CENTER );
484   Vector3 labelAnchoring( AnchorPoint::CENTER );
485   std::string horizontalLabelAlignment = "CENTER";
486   std::string verticalLabelAlignment = "CENTER";
487
488   if( iconExists && label )
489   {
490     // There is an icon and a label to lay out.
491     switch( mIconAlignment )
492     {
493       case LEFT:
494       {
495         iconPosition.x = mIconPadding.left;
496         labelPosition.x = -mLabelPadding.right;
497         iconAnchoring = AnchorPoint::CENTER_LEFT;
498         labelAnchoring = AnchorPoint::CENTER_RIGHT;
499         horizontalLabelAlignment = "END";
500         break;
501       }
502       case RIGHT:
503       {
504         iconPosition.x = -mIconPadding.right;
505         labelPosition.x = mLabelPadding.left;
506         iconAnchoring = AnchorPoint::CENTER_RIGHT;
507         labelAnchoring = AnchorPoint::CENTER_LEFT;
508         horizontalLabelAlignment = "BEGIN";
509         break;
510       }
511       case TOP:
512       {
513         iconPosition.y = mIconPadding.top;
514         labelPosition.y = -mLabelPadding.bottom;
515         iconAnchoring = AnchorPoint::TOP_CENTER;
516         labelAnchoring = AnchorPoint::BOTTOM_CENTER;
517         verticalLabelAlignment = "BOTTOM";
518         break;
519       }
520       case BOTTOM:
521       {
522         iconPosition.y = -mIconPadding.bottom;
523         labelPosition.y = mLabelPadding.top;
524         iconAnchoring = AnchorPoint::BOTTOM_CENTER;
525         labelAnchoring = AnchorPoint::TOP_CENTER;
526         verticalLabelAlignment = "TOP";
527         break;
528       }
529     }
530   }
531
532   // Note: If there is only an icon, or only a label, the default values are now correct.
533   // Setup the icon(s) with the precalculated values.
534   if( icon )
535   {
536     icon.SetPosition( iconPosition );
537     icon.SetParentOrigin( iconAnchoring );
538     icon.SetAnchorPoint( iconAnchoring );
539   }
540   if( selectedIcon )
541   {
542     selectedIcon.SetPosition( iconPosition );
543     selectedIcon.SetParentOrigin( iconAnchoring );
544     selectedIcon.SetAnchorPoint( iconAnchoring );
545   }
546
547   // Setup the label.
548   if( label )
549   {
550     label.SetPosition( labelPosition );
551     label.SetParentOrigin( labelAnchoring );
552     label.SetAnchorPoint( labelAnchoring );
553     label.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, horizontalLabelAlignment );
554     label.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, verticalLabelAlignment );
555   }
556
557   RelayoutRequest();
558 }
559
560 void PushButton::ConfigureSizeNegotiationDimension( Dimension::Type dimension, const std::vector< Actor >& images, Actor& label )
561 {
562   ResizePolicy::Type imageResizePolicy = ResizePolicy::FILL_TO_PARENT;
563   ResizePolicy::Type labelResizePolicy = ResizePolicy::FILL_TO_PARENT;
564
565   ResizePolicy::Type resizePolicy = Self().GetResizePolicy( dimension );
566
567   if( resizePolicy == ResizePolicy::FIT_TO_CHILDREN || resizePolicy == ResizePolicy::USE_NATURAL_SIZE )
568   {
569     if( label )
570     {
571       labelResizePolicy = ResizePolicy::USE_NATURAL_SIZE;
572     }
573     else
574     {
575       imageResizePolicy = ResizePolicy::USE_NATURAL_SIZE;
576     }
577   }
578
579   if( label )
580   {
581     label.SetResizePolicy( labelResizePolicy, dimension );
582   }
583
584   for( std::vector< Actor >::const_iterator it = images.begin(), itEnd = images.end(); it != itEnd; ++it )
585   {
586     Actor actor = *it;
587     if( actor )
588     {
589       actor.SetResizePolicy( imageResizePolicy, dimension );
590     }
591   }
592 }
593
594
595 } // namespace Internal
596
597 } // namespace Toolkit
598
599 } // namespace Dali