TextVisual pixel aligned and uses new shader
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / button-impl.cpp
1 /*
2  * Copyright (c) 2016 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 "button-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/scripting/enum-helper.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/events/touch-data.h>
26 #include <dali/public-api/images/resource-image.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/size-negotiation/relayout-container.h>
30 #include <dali/devel-api/object/property-helper-devel.h>
31 #include <dali/devel-api/scripting/scripting.h>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
35 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
36 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
37 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
38 #include <dali-toolkit/devel-api/align-enums.h>
39 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
40 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
41 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
42 #include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
43 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
44
45 #if defined(DEBUG_ENABLED)
46     Debug::Filter* gLogButtonFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_BUTTON_CONTROL");
47 #endif
48
49 namespace Dali
50 {
51
52 namespace Toolkit
53 {
54
55 namespace Internal
56 {
57
58 namespace
59 {
60
61 BaseHandle Create()
62 {
63   // empty handle as we cannot create button (but type registered for clicked signal)
64   return BaseHandle();
65 }
66
67 // Setup properties, signals and actions using the type-registry.
68 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create )
69
70 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabled",                           BOOLEAN, DISABLED                              )
71 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "autoRepeating",                      BOOLEAN, AUTO_REPEATING                        )
72 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "initialAutoRepeatingDelay",          FLOAT,   INITIAL_AUTO_REPEATING_DELAY          )
73 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "nextAutoRepeatingDelay",             FLOAT,   NEXT_AUTO_REPEATING_DELAY             )
74 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "togglable",                          BOOLEAN, TOGGLABLE                             )
75 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selected",                           BOOLEAN, SELECTED                              )
76 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedStateImage",               MAP,     UNSELECTED_STATE_IMAGE                ) // Deprecated property
77 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedStateImage",                 MAP,     SELECTED_STATE_IMAGE                  ) // Deprecated property
78 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledStateImage",                 MAP,     DISABLED_STATE_IMAGE                  ) // Deprecated property
79 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedColor",                    VECTOR4, UNSELECTED_COLOR                      ) // Deprecated property
80 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedColor",                      VECTOR4, SELECTED_COLOR                        ) // Deprecated property
81 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "label",                              MAP,     LABEL                                 )
82 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "labelText",                          STRING,  LABEL_TEXT                            ) // Deprecated property
83 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedVisual",                   MAP,     UNSELECTED_VISUAL                     )
84 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "selectedVisual",                     MAP,     SELECTED_VISUAL                       )
85 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedVisual",             MAP,     DISABLED_SELECTED_VISUAL              )
86 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedVisual",           MAP,     DISABLED_UNSELECTED_VISUAL            )
87 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedBackgroundVisual",         MAP,     UNSELECTED_BACKGROUND_VISUAL          )
88 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "selectedBackgroundVisual",           MAP,     SELECTED_BACKGROUND_VISUAL            )
89 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedBackgroundVisual", MAP,     DISABLED_UNSELECTED_BACKGROUND_VISUAL )
90 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedBackgroundVisual",   MAP,     DISABLED_SELECTED_BACKGROUND_VISUAL   )
91 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelRelativeAlignment",             STRING,  LABEL_RELATIVE_ALIGNMENT              )
92 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelPadding",                       VECTOR4, LABEL_PADDING                         )
93 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "visualPadding",                      VECTOR4, VISUAL_PADDING                        )
94
95 // Signals:
96 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "pressed",                               SIGNAL_PRESSED               )
97 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "released",                              SIGNAL_RELEASED              )
98 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "clicked",                               SIGNAL_CLICKED               )
99 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "stateChanged",                          SIGNAL_STATE_CHANGED         )
100
101 // Actions:
102 DALI_ACTION_REGISTRATION(   Toolkit, Button, "buttonClick",                           ACTION_BUTTON_CLICK          )
103
104 DALI_TYPE_REGISTRATION_END()
105
106 DALI_ENUM_TO_STRING_TABLE_BEGIN( ALIGNMENT )
107 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BEGIN )
108 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, END )
109 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, TOP )
110 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BOTTOM )
111 DALI_ENUM_TO_STRING_TABLE_END( ALIGNMENT )
112
113 const Scripting::StringEnum ALIGNMENT_STRING_TABLE[] =
114 {
115   { "BEGIN",  Button::BEGIN   },
116   { "END",    Button::END     },
117   { "TOP",    Button::TOP     },
118   { "BOTTOM", Button::BOTTOM  },
119 };
120
121 const unsigned int ALIGNMENT_STRING_TABLE_COUNT = sizeof( ALIGNMENT_STRING_TABLE ) / sizeof( ALIGNMENT_STRING_TABLE[0] );
122
123 const Property::Index GET_VISUAL_INDEX_FOR_STATE[][Button::STATE_COUNT] =
124 {
125   { Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, Toolkit::DevelButton::Property::UNSELECTED_VISUAL },
126   { Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL, Toolkit::DevelButton::Property::SELECTED_VISUAL  },
127   { Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL },
128   { Toolkit::DevelButton::Property::DISABLED_SELECTED_BACKGROUND_VISUAL, Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL }
129 };
130
131 /**
132  * Checks if given map contains a text string
133  */
134 bool MapContainsTextString( Property::Map& map )
135 {
136   bool result = false;
137   Property::Value* value = map.Find( Toolkit::TextVisual::Property::TEXT );
138   if ( value )
139   {
140     std::string textString;
141     value->Get( textString );
142     if ( !textString.empty() )
143     {
144       result = true;
145     }
146   }
147   return result;
148 }
149
150 } // unnamed namespace
151
152 Button::Button()
153 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
154   mAutoRepeatingTimer(),
155   mTextLabelAlignment( END ),
156   mAutoRepeating( false ),
157   mTogglableButton( false ),
158   mTextStringSetFlag( false ),
159   mInitialAutoRepeatingDelay( 0.0f ),
160   mNextAutoRepeatingDelay( 0.0f ),
161   mAnimationTime( 0.0f ),
162   mButtonPressedState( UNPRESSED ),
163   mButtonState( UNSELECTED_STATE ),
164   mPreviousButtonState( mButtonState ),
165   mClickActionPerforming( false )
166 {
167 }
168
169 Button::~Button()
170 {
171 }
172
173 void Button::SetAutoRepeating( bool autoRepeating )
174 {
175   mAutoRepeating = autoRepeating;
176
177   // An autorepeating button can't be a toggle button.
178   if( autoRepeating )
179   {
180     if( IsSelected() )
181     {
182       SetSelected( false ); // UnSelect before switching off Toggle feature.
183     }
184     mTogglableButton = false;
185   }
186 }
187
188 bool Button::IsAutoRepeating() const
189 {
190   return mAutoRepeating;
191 }
192
193 void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
194 {
195   DALI_ASSERT_DEBUG( initialAutoRepeatingDelay > 0.f );
196   mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
197 }
198
199 float Button::GetInitialAutoRepeatingDelay() const
200 {
201   return mInitialAutoRepeatingDelay;
202 }
203
204 void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
205 {
206   DALI_ASSERT_DEBUG( nextAutoRepeatingDelay > 0.f );
207   mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
208 }
209
210 float Button::GetNextAutoRepeatingDelay() const
211 {
212   return mNextAutoRepeatingDelay;
213 }
214
215 void Button::SetTogglableButton( bool togglable )
216 {
217   mTogglableButton = togglable;
218
219   // A toggle button can't be an autorepeating button.
220   if( togglable )
221   {
222     mAutoRepeating = false;
223   }
224 }
225
226 bool Button::IsTogglableButton() const
227 {
228   return mTogglableButton;
229 }
230
231 void Button::SetSelected( bool selected )
232 {
233   if( mTogglableButton )
234   {
235     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetSelected (%s)\n", (selected?"true":"false") );
236
237     if ( selected && ( mButtonState != SELECTED_STATE ) )
238     {
239       ChangeState( SELECTED_STATE );
240     }
241     else if ( !selected && ( mButtonState != UNSELECTED_STATE ) )
242     {
243       ChangeState( UNSELECTED_STATE );
244     }
245   }
246 }
247
248 void Button::SetDisabled( bool disabled )
249 {
250   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetDisabled(%s) state(%d)\n", (disabled)?"disabled":"active", mButtonState );
251
252   if ( disabled )
253   {
254     if ( mButtonState == SELECTED_STATE )
255     {
256       ChangeState( DISABLED_SELECTED_STATE );
257     }
258     else if ( mButtonState == UNSELECTED_STATE )
259     {
260       ChangeState( DISABLED_UNSELECTED_STATE );
261     }
262   }
263   else
264   {
265     if ( mButtonState == DISABLED_SELECTED_STATE )
266     {
267       ChangeState( SELECTED_STATE );
268     }
269     else if ( mButtonState == DISABLED_UNSELECTED_STATE )
270     {
271       ChangeState( UNSELECTED_STATE );
272     }
273   }
274 }
275
276 bool Button::IsDisabled() const
277 {
278   return ( mButtonState == DISABLED_SELECTED_STATE || mButtonState == DISABLED_UNSELECTED_STATE ) ;
279 }
280
281 bool Button::ValidateState( State requestedState )
282 {
283   /*  Below tables shows allowed state transitions
284    *  Match rows in first column to following columns, if true then transition allowed.
285    *  eg UNSELECTED_STATE to DISABLED_UNSELECTED_STATE is true so state transition allowed.
286    *
287                                                              to| UNSELECTED_STATE | SELECTED_STATE | DISABLED_UNSELECTED_STATE | DISABLED_SELECTED_STATE |*/
288                                  /* from*/
289   bool transitionTable[4][4] = { /* UNSELECTED_STATE*/         {      false,            true,               true,                   false         },
290                                  /* SELECTED_STATE*/           {      true,             false,              false,                  true          },
291                                  /* DISABLED_UNSELECTED_STATE*/{      true,             true,               false,                  false         },
292                                  /* DISABLED_SELECTED_STATE*/  {      false,            true,               false,                  false         }
293                                };
294
295   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ValidateState ReuestedState:%d, CurrentState:%d, result:%s\n",
296                  requestedState, mButtonState, (transitionTable[mButtonState][requestedState])?"change-accepted":"change-denied");
297
298   return transitionTable[mButtonState][requestedState];
299 }
300
301 void Button::PerformFunctionOnVisualsInState( void(Button::*functionPtr)( Property::Index visualIndex), State state )
302 {
303   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::PerformFunctionOnVisualsInState BACKROUND visual(%d) for state (%d)\n",
304                  GET_VISUAL_INDEX_FOR_STATE[state][BACKGROUND], state );
305   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::PerformFunctionOnVisualsInState FOREGROUND visuals(%d)  for state (%d)\n",
306                  GET_VISUAL_INDEX_FOR_STATE[state][FOREGROUND], state );
307
308   (this->*functionPtr)( GET_VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
309   (this->*functionPtr)( GET_VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
310
311   RelayoutRequest();
312 }
313
314 void Button::ChangeState( State requestedState )
315 {
316   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d)\n", requestedState );
317
318   // Validate State before changing
319   if ( !ValidateState( requestedState ))
320   {
321     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d) not validated\n", requestedState );
322     return;
323   }
324
325   // If not on stage the button could have still been set to selected so update state
326   mPreviousButtonState = mButtonState; // Store previous state for visual removal (used when animations ended)
327   mButtonState = requestedState; // Update current state
328
329   if ( Self().OnStage() )
330   {
331     OnStateChange( mButtonState ); // Notify derived buttons
332     PerformFunctionOnVisualsInState( &Button::SelectRequiredVisual, mButtonState );
333     // If animation supported then visual removal should be performed after any transition animation has completed.
334     // If Required Visual is not loaded before current visual is removed then a flickering will be evident.
335     PerformFunctionOnVisualsInState( &Button::OnButtonVisualRemoval, mPreviousButtonState ); // Derived button can override OnButtonVisualRemoval
336   }
337
338   Toolkit::Button handle( GetOwner() );
339   // Emit signal.
340   mStateChangedSignal.Emit( handle );
341 }
342
343 bool Button::IsSelected() const
344 {
345   bool selected = ( mButtonState == SELECTED_STATE ) || ( mButtonState == DISABLED_SELECTED_STATE );
346   return mTogglableButton && selected;
347 }
348
349 void Button::SetLabelText( const std::string& label )
350 {
351   Property::Map labelProperty;
352   labelProperty.Add( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::TEXT)
353                .Add( Toolkit::TextVisual::Property::TEXT, label );
354
355   Self().SetProperty( Toolkit::Button::Property::LABEL, labelProperty );
356 }
357
358 std::string Button::GetLabelText() const
359 {
360   Property::Value value = Self().GetProperty( Toolkit::Button::Property::LABEL );
361
362   Property::Map *labelProperty = value.GetMap();
363
364   std::string textLabel;
365
366   if ( labelProperty )
367   {
368     Property::Value* value = labelProperty->Find( Toolkit::TextVisual::Property::TEXT );
369     value->Get( textLabel );
370   }
371
372   return textLabel;
373 }
374
375 void Button::MergeLabelProperties( const Property::Map& inMap, Property::Map& outMap )
376 {
377   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties with %d properties\n", inMap.Count() );
378
379   /**
380    * Properties for the Label visual could be from a style sheet but after being set the "TEXT" property could be set.
381    * Hence would need to create the Text Visual with the complete merged set of properties.
382    *
383    * 1) Find Label Visual
384    * 2) Retrieve current properties ( settings )
385    * 3) Merge with new properties ( settings )
386    * 4) Return new merged map
387    */
388   Toolkit::Visual::Base visual = GetVisual( Toolkit::Button::Property::LABEL );
389   if ( visual )
390   {
391     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties Visual already exists, retrieving existing map\n");
392     visual.CreatePropertyMap( outMap );
393     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties retrieved %d properties\n", outMap.Count() );
394   }
395
396   outMap.Merge( inMap );
397
398   // Store if a text string has been supplied.
399
400   mTextStringSetFlag = MapContainsTextString( outMap );
401
402   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties now has %d properties\n", outMap.Count() );
403 }
404
405 void Button::SetLabelAlignment( Button::Align labelAlignment)
406 {
407   mTextLabelAlignment = labelAlignment;
408   RelayoutRequest();
409 }
410
411 Button::Align Button::GetLabelAlignment()
412 {
413   return mTextLabelAlignment;
414 }
415
416 /**
417  * Create Visual for given index from a property map or url.
418  * 1) Check if value passed in is a url and create visual
419  * 2) Create visual from map if step (1) is false
420  * 3) Register visual with control with false for enable flag. Button will later enable visual when needed ( Button::SelectRequiredVisual )
421  * 4) Unregister visual if empty map was provided. This is the method to remove a visual
422  */
423
424 void Button::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const float visualDepth )
425 {
426   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent index(%d)\n", index );
427   Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
428   Toolkit::Visual::Base buttonVisual;
429
430   std::string imageUrl;
431   if( value.Get( imageUrl ) )
432   {
433     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using image URL(%d)\n", index );
434     if ( !imageUrl.empty() )
435     {
436       DALI_ASSERT_DEBUG( index != Toolkit::Button::Property::LABEL && "Creating a Image Visual instead of Text Visual " );
437       buttonVisual = visualFactory.CreateVisual(  imageUrl, ImageDimensions()  );
438     }
439   }
440   else
441   {
442     // if its not a string then get a Property::Map from the property if possible.
443     Property::Map *map = value.GetMap();
444     if( map && !map->Empty()  ) // Empty map results in current visual removal.
445     {
446       DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using Map(%d)\n", index );
447       buttonVisual = visualFactory.CreateVisual( *map );
448     }
449   }
450
451   if ( buttonVisual )
452   {
453     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent RegisterVisual index(%d) enabled(%s)\n",
454                    index, IsVisualEnabled( index )?"true":"false" );
455     buttonVisual.SetDepthIndex( visualDepth );
456     RegisterVisual( index, buttonVisual, IsVisualEnabled( index ) );
457   }
458   else
459   {
460     UnregisterVisual( index );
461     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "CreateVisualsForComponent Visual not created or empty map (clearing visual).(%d)\n", index);
462   }
463   PerformFunctionOnVisualsInState( &Button::SelectRequiredVisual, mButtonState );
464 }
465
466 bool Button::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
467 {
468   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual visual(%d)\n", visualIndex);
469   bool success = false;
470   Toolkit::Visual::Base visual = GetVisual( visualIndex );
471   if ( visual )
472   {
473     visual.CreatePropertyMap( retreivedMap );
474     success = true;
475   }
476   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual %s\n", success?"Success":"Failure");
477   return success;
478 }
479
480 bool Button::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
481 {
482   bool ret = false;
483
484   Dali::BaseHandle handle( object );
485
486   Toolkit::Button button = Toolkit::Button::DownCast( handle );
487
488   DALI_ASSERT_DEBUG( button );
489
490   if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
491   {
492     ret = GetImplementation( button ).DoClickAction( attributes );
493   }
494
495   return ret;
496 }
497
498 bool Button::DoClickAction( const Property::Map& attributes )
499 {
500   // Prevents the button signals from doing a recursive loop by sending an action
501   // and re-emitting the signals.
502   if( !mClickActionPerforming )
503   {
504     mClickActionPerforming = true;
505     ButtonDown();
506     if ( !mTogglableButton )
507     {
508       mButtonPressedState = DEPRESSED;
509     }
510     ButtonUp();
511     mClickActionPerforming = false;
512
513     return true;
514   }
515
516   return false;
517 }
518
519 void Button::ButtonDown()
520 {
521   if( mTogglableButton )
522   {
523     if ( mButtonState != SELECTED_STATE )
524     {
525       SetSelected( true );
526       mButtonPressedState = TOGGLE_DEPRESSED;
527     }
528     else
529     {
530       mButtonPressedState = DEPRESSED;
531     }
532   }
533   else
534   {
535     Pressed();
536     mButtonPressedState = DEPRESSED;
537     if( mAutoRepeating )
538     {
539        SetUpTimer( mInitialAutoRepeatingDelay );
540     }
541   }
542
543   // The pressed signal should be emitted regardless of toggle mode.
544   Toolkit::Button handle( GetOwner() );
545   mPressedSignal.Emit( handle );
546 }
547
548 void Button::ButtonUp()
549 {
550   if( DEPRESSED == mButtonPressedState )
551   {
552     bool validButtonAction = false;
553
554     if( mTogglableButton ) // Button up will change state
555     {
556       validButtonAction = OnToggleReleased(); // Derived toggle buttons can override this to provide custom behaviour
557     }
558     else
559     {
560       Released(); // Button up will result in unselected state
561       if( mAutoRepeating )
562       {
563         mAutoRepeatingTimer.Reset();
564       }
565       validButtonAction = true;
566     }
567
568     if ( validButtonAction )
569     {
570       // The clicked and released signals should be emitted regardless of toggle mode.
571       Toolkit::Button handle( GetOwner() );
572       mReleasedSignal.Emit( handle );
573       mClickedSignal.Emit( handle );
574     }
575   }
576 }
577
578 bool Button::OnToggleReleased()
579 {
580   SetSelected( !IsSelected() );
581   mButtonPressedState = UNPRESSED;
582   return true;
583 }
584
585
586 void Button::OnTouchPointLeave()
587 {
588   if( DEPRESSED == mButtonPressedState )
589   {
590     if( !mTogglableButton )
591     {
592       Released();
593
594       if( mAutoRepeating )
595       {
596         mAutoRepeatingTimer.Reset();
597       }
598     }
599
600     mButtonPressedState = UNPRESSED;
601
602     // The released signal should be emitted regardless of toggle mode.
603     Toolkit::Button handle( GetOwner() );
604     mReleasedSignal.Emit( handle );
605   }
606 }
607
608 void Button::OnTouchPointInterrupted()
609 {
610   OnTouchPointLeave();
611 }
612
613 Toolkit::Button::ButtonSignalType& Button::PressedSignal()
614 {
615   return mPressedSignal;
616 }
617
618 Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
619 {
620   return mReleasedSignal;
621 }
622
623 Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
624 {
625   return mClickedSignal;
626 }
627
628 Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
629 {
630   return mStateChangedSignal;
631 }
632
633 bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
634 {
635   Dali::BaseHandle handle( object );
636
637   bool connected( true );
638   Toolkit::Button button = Toolkit::Button::DownCast( handle );
639
640   if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
641   {
642     button.PressedSignal().Connect( tracker, functor );
643   }
644   else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
645   {
646     button.ReleasedSignal().Connect( tracker, functor );
647   }
648   else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
649   {
650     button.ClickedSignal().Connect( tracker, functor );
651   }
652   else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
653   {
654     button.StateChangedSignal().Connect( tracker, functor );
655   }
656   else
657   {
658     // signalName does not match any signal
659     connected = false;
660   }
661
662   return connected;
663 }
664
665 void Button::OnInitialize()
666 {
667   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnInitialize\n" );
668
669   Actor self = Self();
670
671   mTapDetector = TapGestureDetector::New();
672   mTapDetector.Attach( self );
673   mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
674
675   self.SetKeyboardFocusable( true );
676
677   self.TouchSignal().Connect( this, &Button::OnTouch );
678 }
679
680 bool Button::OnAccessibilityActivated()
681 {
682   return OnKeyboardEnter();
683 }
684
685 bool Button::OnTouch( Actor actor, const TouchData& touch )
686 {
687
688   // Only events are processed when the button is not disabled and the touch event has only
689   // one touch point.
690
691   if( !IsDisabled() && ( 1 == touch.GetPointCount() ) )
692   {
693     switch( touch.GetState( 0 ) )
694     {
695       case PointState::DOWN:
696       {
697         ButtonDown();
698         break;
699       }
700       case PointState::UP:
701       {
702         ButtonUp();
703         break;
704       }
705       case PointState::INTERRUPTED:
706       {
707         OnTouchPointInterrupted();
708         break;
709       }
710       case PointState::LEAVE:
711       {
712         OnTouchPointLeave();
713         break;
714       }
715       case PointState::MOTION:
716       case PointState::STATIONARY: // FALLTHROUGH
717       {
718         // Nothing to do
719         break;
720       }
721     }
722   }
723   else if( 1 < touch.GetPointCount() )
724   {
725     OnTouchPointLeave(); // Notification for derived classes.
726
727     // Sets the button state to the default
728     mButtonPressedState = UNPRESSED;
729   }
730
731   return false;
732 }
733
734 bool Button::OnKeyboardEnter()
735 {
736   // When the enter key is pressed, or button is activated, the click action is performed.
737   Property::Map attributes;
738   bool ret = DoClickAction( attributes );
739
740   return ret;
741 }
742
743 void Button::OnStageDisconnection()
744 {
745   if( DEPRESSED == mButtonPressedState )
746   {
747     if( !mTogglableButton )
748     {
749       Released();
750
751       if( mAutoRepeating )
752       {
753         mAutoRepeatingTimer.Reset();
754       }
755     }
756   }
757
758   mButtonPressedState = UNPRESSED;
759
760   Control::OnStageDisconnection(); // Visuals will be set off stage
761 }
762
763 void Button::OnStageConnection( int depth )
764 {
765   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnStageConnection ptr(%p) \n", this );
766   PerformFunctionOnVisualsInState( &Button::OnButtonVisualRemoval, mPreviousButtonState );
767   SelectRequiredVisual( Toolkit::Button::Property::LABEL );
768   PerformFunctionOnVisualsInState( &Button::SelectRequiredVisual, mButtonState );
769   Control::OnStageConnection( depth ); // Enabled visuals will be put on stage
770 }
771
772 Vector3 Button::GetNaturalSize()
773 {
774   Vector3 size = Vector3::ZERO;
775
776   bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side
777
778   // Get natural size of foreground ( largest of the possible visuals )
779   Size largestProvidedVisual;
780   Size labelSize = Size::ZERO;
781
782   bool foreGroundVisualUsed = false;
783
784   for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
785   {
786     Toolkit::Visual::Base visual = GetVisual( GET_VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
787     Size visualSize;
788     if ( visual )
789     {
790       visual.GetNaturalSize( visualSize );
791       largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
792       largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
793       foreGroundVisualUsed = true;
794     }
795   }
796
797   if ( !foreGroundVisualUsed ) // If foreground visual not supplied then use the background visual to calculate Natural size
798   {
799     for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
800     {
801       Toolkit::Visual::Base visual = GetVisual( GET_VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
802       Size visualSize;
803       if ( visual )
804       {
805         visual.GetNaturalSize( visualSize );
806         largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
807         largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
808       }
809     }
810   }
811
812   // Get horizontal padding total
813   if ( largestProvidedVisual.width > 0 )  // if visual exists
814   {
815     size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right;
816   }
817   // Get vertical padding total
818   if ( largestProvidedVisual.height > 0 )
819   {
820     size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom;
821   }
822
823   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n",
824                  largestProvidedVisual.width, largestProvidedVisual.height );
825
826   // Get natural size of label if text has been set
827   if ( mTextStringSetFlag )
828   {
829     Toolkit::Visual::Base visual = GetVisual( Toolkit::Button::Property::LABEL );
830
831     if ( visual )
832     {
833       visual.GetNaturalSize( labelSize );
834
835       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n",
836                      labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom);
837
838       labelSize.width += mLabelPadding.left + mLabelPadding.right;
839       labelSize.height += mLabelPadding.top + mLabelPadding.bottom;
840
841       // Add label size to height or width depending on alignment position
842       if ( horizontalAlignment )
843       {
844         size.width += labelSize.width;
845         size.height = std::max(size.height, labelSize.height );
846       }
847       else
848       {
849         size.height += labelSize.height;
850         size.width = std::max(size.width, labelSize.width );
851       }
852     }
853   }
854
855   if( size.width < 1 && size.height < 1 )
856   {
857     // if no image or label then use Control's natural size
858     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n");
859     size = Control::GetNaturalSize();
860   }
861
862   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height );
863
864   return size;
865 }
866
867 void Button::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
868 {
869   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnSetResizePolicy\n");
870   RelayoutRequest();
871 }
872
873 /**
874  * Visuals are sized and positioned in this function.
875  * Whilst the control has it's size negotiated it has to size it's visuals explicitly here.
876  */
877
878 void Button::OnRelayout( const Vector2& size, RelayoutContainer& container )
879 {
880   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState );
881
882   Toolkit::Visual::Base currentVisual = GetVisual( GET_VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND] );
883
884   Toolkit::Visual::Base currentBackGroundVisual = GetVisual( GET_VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND] );
885
886   // Sizes and padding set to zero, if not present then values will no effect calculations.
887   Vector2 visualPosition = Vector2::ZERO;
888   Vector2 labelPosition = Vector2::ZERO;
889   Size visualSize = Size::ZERO;
890   Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
891   Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
892
893   if ( mTextStringSetFlag )
894   {
895     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width,mLabelPadding.height );
896     labelVisualPadding = mLabelPadding;
897   }
898
899   if ( currentVisual )
900   {
901     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width,mForegroundPadding.height );
902     currentVisual.GetNaturalSize( visualSize );
903     foregroundVisualPadding = mForegroundPadding;
904   }
905
906   Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
907
908   Vector2 visualAndPaddingSize = Vector2( ( foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y ),
909                                           ( foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height ));
910
911   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height);
912
913   // Text Visual should take all space available after foreground visual size and all padding is considered.
914   // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual.
915   Size remainingSpaceForText = Size::ZERO;
916
917   switch ( mTextLabelAlignment )
918   {
919     case BEGIN :
920     {
921       visualAnchorPoint = Toolkit::Align::TOP_END;
922       visualPosition.x = foregroundVisualPadding.right;
923       visualPosition.y = foregroundVisualPadding.top;
924
925       labelPosition.x = labelVisualPadding.x;
926       labelPosition.y = labelVisualPadding.top;
927
928       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
929       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
930       break;
931     }
932     case END :
933     {
934       visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
935       visualPosition.x = foregroundVisualPadding.left;
936       visualPosition.y = foregroundVisualPadding.top;
937
938       labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x;
939       labelPosition.y = labelVisualPadding.top;
940
941       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
942       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
943       break;
944     }
945     case TOP :
946     {
947       visualAnchorPoint = Toolkit::Align::BOTTOM_END;
948       visualPosition.x = foregroundVisualPadding.left;
949       visualPosition.y = foregroundVisualPadding.bottom;
950
951       labelPosition.x = labelVisualPadding.left;
952       labelPosition.y = labelVisualPadding.top;
953
954       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
955       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
956
957       break;
958     }
959     case BOTTOM :
960     {
961       visualAnchorPoint = Toolkit::Align::TOP_END;
962       visualPosition.x = foregroundVisualPadding.left;
963       visualPosition.y = foregroundVisualPadding.top;
964
965       labelPosition.x = labelVisualPadding.left;
966       labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top;
967
968       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
969       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
970
971       break;
972     }
973   }
974
975   if ( currentBackGroundVisual )
976   {
977     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height);
978
979     Property::Map visualTransform;
980
981     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, size )
982                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 0.0f, 0.0f, 1.0f, 1.0f) );  // Use relative size
983
984     currentBackGroundVisual.SetTransformAndSize( visualTransform, size );
985   }
986
987   if ( currentVisual )
988   {
989     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height);
990
991     Property::Map visualTransform;
992
993     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, visualSize )
994                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET, visualPosition )
995                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f) )  // Use absolute size
996                    .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
997                    .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
998
999     currentVisual.SetTransformAndSize( visualTransform, size );
1000   }
1001
1002   if ( mTextStringSetFlag )
1003   {
1004     Toolkit::Visual::Base textVisual = GetVisual( Toolkit::Button::Property::LABEL ); // No need to search for Label visual if no text set.
1005
1006     if ( textVisual )
1007     {
1008       if ( !currentVisual )
1009       {
1010         DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Only Text\n");
1011         labelPosition.x = labelVisualPadding.left;
1012         labelPosition.y = labelVisualPadding.height;
1013       }
1014
1015       Vector2 preSize = Vector2( static_cast< int >( remainingSpaceForText.x ), static_cast< int >( remainingSpaceForText.y ));
1016
1017       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y);
1018
1019       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y);
1020
1021
1022       Property::Map textVisualTransform;
1023       textVisualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, preSize )
1024                          .Add( Toolkit::DevelVisual::Transform::Property::OFFSET, labelPosition )
1025                          .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f,1.0f ) ) // Use absolute size
1026                          .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
1027                          .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
1028
1029       textVisual.SetTransformAndSize( textVisualTransform, size );
1030     }
1031   }
1032
1033   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout << \n");
1034 }
1035
1036 void Button::OnTap(Actor actor, const TapGesture& tap)
1037 {
1038   // Prevents Parent getting a tap event
1039 }
1040
1041 void Button::SetUpTimer( float delay )
1042 {
1043   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
1044   mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
1045   mAutoRepeatingTimer.Start();
1046 }
1047
1048 bool Button::AutoRepeatingSlot()
1049 {
1050   bool consumed = false;
1051   if( !IsDisabled() )
1052   {
1053     // Restart the autorepeat timer.
1054     SetUpTimer( mNextAutoRepeatingDelay );
1055
1056     Pressed();
1057
1058     Toolkit::Button handle( GetOwner() );
1059
1060     //Emit signal.
1061     consumed = mReleasedSignal.Emit( handle );
1062     consumed = mClickedSignal.Emit( handle );
1063     consumed |= mPressedSignal.Emit( handle );
1064  }
1065
1066   return consumed;
1067 }
1068
1069 void Button::Pressed()
1070 {
1071   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Pressed\n" );
1072
1073   if( mButtonState == UNSELECTED_STATE )
1074   {
1075     ChangeState( SELECTED_STATE );
1076     OnPressed();  // Notifies the derived class the button has been pressed.
1077   }
1078 }
1079
1080 void Button::Released()
1081 {
1082   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Released\n" );
1083
1084   if( mButtonState == SELECTED_STATE && !mTogglableButton )
1085   {
1086     ChangeState( UNSELECTED_STATE );
1087     OnReleased(); //    // Notifies the derived class the button has been released.
1088   }
1089   mButtonPressedState = UNPRESSED;
1090 }
1091
1092 void Button::SelectRequiredVisual( Property::Index visualIndex )
1093 {
1094   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1095
1096   EnableVisual( visualIndex, true );
1097 }
1098
1099 void Button::RemoveVisual( Property::Index visualIndex )
1100 {
1101   // Use OnButtonVisualRemoval if want button developer to have the option to override removal.
1102   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1103
1104   Toolkit::Visual::Base visual = GetVisual( visualIndex );
1105
1106   if( visual )
1107   {
1108     EnableVisual( visualIndex, false );
1109   }
1110 }
1111
1112 void Button::OnButtonVisualRemoval( Property::Index visualIndex )
1113 {
1114   // Derived Buttons can over ride this to prevent default removal.
1115   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex );
1116   RemoveVisual( visualIndex );
1117 }
1118
1119 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
1120 {
1121   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1122
1123   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index );
1124
1125   if ( button )
1126   {
1127     switch ( index )
1128     {
1129       case Toolkit::Button::Property::DISABLED:
1130       {
1131         GetImplementation( button ).SetDisabled( value.Get< bool >() );
1132         break;
1133       }
1134
1135       case Toolkit::Button::Property::AUTO_REPEATING:
1136       {
1137         GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
1138         break;
1139       }
1140
1141       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1142       {
1143         GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
1144         break;
1145       }
1146
1147       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1148       {
1149         GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
1150         break;
1151       }
1152
1153       case Toolkit::Button::Property::TOGGLABLE:
1154       {
1155         GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
1156         break;
1157       }
1158
1159       case Toolkit::Button::Property::SELECTED:
1160       {
1161         GetImplementation( button ).SetSelected( value.Get< bool >() );
1162         break;
1163       }
1164
1165       case Toolkit::Button::Property::UNSELECTED_STATE_IMAGE: // Legacy Tizen 3.0
1166       {
1167         GetImplementation( button ).CreateVisualsForComponent( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, value, DepthIndex::BACKGROUND );
1168         break;
1169       }
1170       case Toolkit::Button::Property::DISABLED_STATE_IMAGE:  // Legacy Tizen 3.0
1171       {
1172         GetImplementation( button ).CreateVisualsForComponent( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, value, DepthIndex::BACKGROUND );
1173         break;
1174       }
1175       case Toolkit::Button::Property::SELECTED_STATE_IMAGE:  // Legacy Tizen 3.0
1176       {
1177         GetImplementation( button ).CreateVisualsForComponent( Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL, value, DepthIndex::BACKGROUND );
1178         break;
1179       }
1180       case Toolkit::DevelButton::Property::UNSELECTED_VISUAL:
1181       case Toolkit::DevelButton::Property::SELECTED_VISUAL:
1182       case Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL:
1183       case Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL:
1184       {
1185         GetImplementation( button ).CreateVisualsForComponent( index, value, DepthIndex::CONTENT );
1186         break;
1187       }
1188
1189       case Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL:
1190       case Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL:
1191       case Toolkit::DevelButton::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1192       case Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1193       {
1194         GetImplementation( button ).CreateVisualsForComponent( index , value, DepthIndex::BACKGROUND);
1195         break;
1196       }
1197
1198       case Toolkit::Button::Property::UNSELECTED_COLOR:
1199       {
1200         DALI_LOG_WARNING("[%s] Using deprecated Property Button::Property::UNSELECTED_COLOR instead use Button::Property::UNSELECTED_BACKGROUND_VISUAL\n", __FUNCTION__);
1201         GetImplementation( button ).SetColor( value.Get< Vector4 >(), Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL );
1202         break;
1203       }
1204
1205       case Toolkit::Button::Property::SELECTED_COLOR:
1206       {
1207         DALI_LOG_WARNING("[%s] Using deprecated Property Button::Property::SELECTED_COLOR instead use Button::Property::SELECTED_BACKGROUND_VISUAL\n", __FUNCTION__);
1208         GetImplementation( button ).SetColor( value.Get< Vector4 >(), Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL );
1209         break;
1210       }
1211
1212       case Toolkit::Button::Property::LABEL_TEXT:
1213       {
1214         DALI_LOG_WARNING("[%s] Using deprecated Property Button::Property::LABEL_TEXT instead use Button::Property::LABEL\n", __FUNCTION__);
1215         GetImplementation( button ).SetLabelText(value.Get< std::string >() );
1216         break;
1217       }
1218
1219       case Toolkit::Button::Property::LABEL:
1220       {
1221         // Get a Property::Map from the property if possible.
1222         Property::Map* setPropertyMap = value.GetMap();
1223         if( setPropertyMap )
1224         {
1225           Property::Map textVisualProperties;
1226           GetImplementation( button ).MergeLabelProperties( *setPropertyMap, textVisualProperties );
1227           GetImplementation( button ).CreateVisualsForComponent( index, textVisualProperties, DepthIndex::CONTENT );
1228           GetImplementation( button ).RelayoutRequest();
1229         }
1230         break;
1231       }
1232
1233       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1234       {
1235         Button::Align labelAlignment(END);
1236         Scripting::GetEnumeration< Button::Align> ( value.Get< std::string >().c_str(),
1237                                                     ALIGNMENT_TABLE, ALIGNMENT_TABLE_COUNT,
1238                                                     labelAlignment );
1239
1240         GetImplementation( button ).SetLabelAlignment( labelAlignment );
1241         GetImplementation( button ).RelayoutRequest();
1242         break;
1243       }
1244
1245       case Toolkit::DevelButton::Property::LABEL_PADDING:
1246       {
1247         Vector4 padding ( value.Get< Vector4 >() );
1248         GetImplementation( button ).SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1249         break;
1250       }
1251
1252       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1253       {
1254         Vector4 padding ( value.Get< Vector4 >() );
1255         GetImplementation( button ).SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1256         GetImplementation( button ).RelayoutRequest();
1257         break;
1258       }
1259     }
1260   }
1261 }
1262
1263 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
1264 {
1265   Property::Value value;
1266
1267   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1268
1269   if ( button )
1270   {
1271     switch ( propertyIndex )
1272     {
1273       case Toolkit::Button::Property::DISABLED:
1274       {
1275         value = GetImplementation( button ).IsDisabled();
1276         break;
1277       }
1278
1279       case Toolkit::Button::Property::AUTO_REPEATING:
1280       {
1281         value = GetImplementation( button ).mAutoRepeating;
1282         break;
1283       }
1284
1285       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1286       {
1287         value = GetImplementation( button ).mInitialAutoRepeatingDelay;
1288         break;
1289       }
1290
1291       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1292       {
1293         value = GetImplementation( button ).mNextAutoRepeatingDelay;
1294         break;
1295       }
1296
1297       case Toolkit::Button::Property::TOGGLABLE:
1298       {
1299         value = GetImplementation( button ).mTogglableButton;
1300         break;
1301       }
1302
1303       case Toolkit::Button::Property::SELECTED:
1304       {
1305         value = GetImplementation( button ).IsSelected();
1306         break;
1307       }
1308
1309       case Toolkit::Button::Property::UNSELECTED_STATE_IMAGE:
1310       {
1311         value = GetImplementation( button ).GetUrlForImageVisual( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL );
1312         break;
1313       }
1314
1315       case Toolkit::Button::Property::SELECTED_STATE_IMAGE:
1316       {
1317         value = GetImplementation( button ).GetUrlForImageVisual( Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL );
1318         break;
1319       }
1320
1321       case Toolkit::Button::Property::DISABLED_STATE_IMAGE:
1322       {
1323         value = GetImplementation( button ).GetUrlForImageVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL );
1324         break;
1325       }
1326
1327       case Toolkit::DevelButton::Property::UNSELECTED_VISUAL:
1328       case Toolkit::DevelButton::Property::SELECTED_VISUAL:
1329       case Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL:
1330       case Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL:
1331       case Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL:
1332       case Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL:
1333       case Toolkit::DevelButton::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1334       case Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1335       case Toolkit::Button::Property::LABEL:
1336       {
1337         Property::Map visualProperty;
1338         if ( GetImplementation( button ).GetPropertyMapForVisual( propertyIndex, visualProperty ) )
1339         {
1340           value = visualProperty;
1341         }
1342         break;
1343       }
1344
1345       case Toolkit::Button::Property::UNSELECTED_COLOR:
1346       {
1347         value = GetImplementation( button ).GetUnselectedColor();
1348         break;
1349       }
1350
1351       case Toolkit::Button::Property::SELECTED_COLOR:
1352       {
1353         value = GetImplementation( button ).GetSelectedColor();
1354         break;
1355       }
1356
1357       case Toolkit::Button::Property::LABEL_TEXT:
1358       {
1359         value = GetImplementation( button ).GetLabelText();
1360         break;
1361       }
1362
1363       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1364       {
1365         const char* alignment = Scripting::GetEnumerationName< Button::Align >( GetImplementation( button ).GetLabelAlignment(),
1366                                                                                 ALIGNMENT_STRING_TABLE,
1367                                                                                 ALIGNMENT_STRING_TABLE_COUNT );
1368         if( alignment )
1369         {
1370           value = std::string( alignment );
1371         }
1372
1373         break;
1374       }
1375
1376       case Toolkit::DevelButton::Property::LABEL_PADDING:
1377       {
1378         Padding padding = GetImplementation( button ).GetLabelPadding();
1379         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1380         break;
1381       }
1382
1383       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1384       {
1385         Padding padding = GetImplementation( button ).GetForegroundPadding();
1386         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1387       }
1388     }
1389   }
1390
1391   return value;
1392 }
1393
1394 void Button::SetLabelPadding( const Padding& padding)
1395 {
1396   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1397   mLabelPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1398   RelayoutRequest();
1399 }
1400
1401 Padding Button::GetLabelPadding()
1402 {
1403   return mLabelPadding;
1404 }
1405
1406 void Button::SetForegroundPadding( const Padding& padding)
1407 {
1408   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1409   mForegroundPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1410   RelayoutRequest();
1411 }
1412
1413 Padding Button::GetForegroundPadding()
1414 {
1415   return mForegroundPadding;
1416 }
1417
1418 ////////////////////////////////////////////////////////////////////////
1419 // Legacy functions from Tizen 2.4 and 3.0
1420
1421 // Legacy code needed whilst Color can be set by direct Property setting ( deprecated ) instead of setting a Visual
1422 void Button::SetColor( const Vector4& color, Property::Index visualIndex )
1423 {
1424   if ( visualIndex == Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL )
1425   {
1426     mSelectedColor = color;
1427   }
1428   else
1429   {
1430     mUnselectedColor = color;
1431   }
1432
1433   Property::Map map;
1434   map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
1435   map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
1436
1437   CreateVisualsForComponent( visualIndex, map, DepthIndex::BACKGROUND );
1438 }
1439
1440 const Vector4 Button::GetUnselectedColor() const
1441 {
1442   return mUnselectedColor;
1443 }
1444
1445 const Vector4 Button::GetSelectedColor() const
1446 {
1447   return mSelectedColor;
1448 }
1449
1450 void Button::SetAnimationTime( float animationTime )
1451 {
1452   // Used by deprecated API
1453   mAnimationTime = animationTime;
1454 }
1455
1456 float Button::GetAnimationTime() const
1457 {
1458   // Used by deprecated API
1459   return mAnimationTime;
1460 }
1461
1462 void Button::SetLabel( Actor label )
1463 {
1464   if ( label )
1465   {
1466     Property::Value value ="";
1467     value = label.GetProperty(Toolkit::TextLabel::Property::TEXT);
1468
1469     SetLabelText( value.Get<std::string>() );
1470   }
1471 }
1472
1473 void Button::SetUnselectedImage( const std::string& filename )
1474 {
1475   SetBackgroundImage( filename );
1476 }
1477
1478 void Button::SetBackgroundImage( const std::string& filename )
1479 {
1480   if( !filename.empty() )
1481   {
1482     CreateVisualsForComponent( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, filename, DepthIndex::BACKGROUND );
1483   }
1484   else
1485   {
1486     UnregisterVisual( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL );
1487   }
1488 }
1489
1490 void Button::SetSelectedImage( const std::string& filename )
1491 {
1492     SetSelectedBackgroundImage( filename );
1493 }
1494
1495 void Button::SetSelectedBackgroundImage( const std::string& filename )
1496 {
1497   if( !filename.empty() )
1498   {
1499     CreateVisualsForComponent( Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL, filename, DepthIndex::BACKGROUND );
1500   }
1501   else
1502   {
1503     UnregisterVisual( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL );
1504   }
1505 }
1506
1507 void Button::SetDisabledBackgroundImage( const std::string& filename )
1508 {
1509   if( !filename.empty() )
1510   {
1511     CreateVisualsForComponent( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, filename, DepthIndex::BACKGROUND );
1512   }
1513 }
1514
1515 void Button::SetDisabledImage( const std::string& filename )
1516 {
1517   if( !filename.empty() )
1518   {
1519     CreateVisualsForComponent( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, filename, DepthIndex::CONTENT );
1520   }
1521 }
1522
1523 void Button::SetDisabledSelectedImage( const std::string& filename )
1524 {
1525   if( !filename.empty() )
1526   {
1527     CreateVisualsForComponent( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, filename, DepthIndex::CONTENT );
1528   }
1529 }
1530
1531 // Used by Deprecated Properties which don't use the Visual Property maps for setting and getting
1532 std::string Button::GetUrlForImageVisual( const Property::Index index ) const
1533 {
1534   Toolkit::Visual::Base visual = GetVisual( index );
1535   std::string result;
1536
1537   if ( visual )
1538   {
1539     Dali::Property::Map retreivedMap;
1540     visual.CreatePropertyMap( retreivedMap );
1541     Property::Value* value = retreivedMap.Find(  Toolkit::ImageVisual::Property::URL,  Property::STRING );
1542     if ( value )
1543     {
1544       result = value->Get<std::string>();
1545     }
1546   }
1547
1548   return result;
1549 }
1550
1551 // Below functions DEPRECATED_1_0.50 - Return empty Actors
1552
1553 namespace
1554 {
1555 std::string GetUrlFromImage( Image& image )
1556 {
1557   ResourceImage resourceImage = ResourceImage::DownCast( image );
1558
1559   std::string imageUrl;
1560
1561   if ( resourceImage )
1562   {
1563     imageUrl = resourceImage.GetUrl();
1564   }
1565   return imageUrl;
1566 }
1567
1568 } // namespace
1569
1570
1571 void Button::SetButtonImage( Image image )
1572 {
1573   DALI_LOG_WARNING("Button::SetButtonImage @DEPRECATED_1_0.50\n");
1574   SetUnselectedImage( GetUrlFromImage( image ) );
1575 }
1576
1577 void Button::SetSelectedImage( Image image )
1578 {
1579   DALI_LOG_WARNING("Button::SetSelectedImage @DEPRECATED_1_0.50\n");
1580   SetSelectedImage( GetUrlFromImage( image ) );
1581 }
1582
1583 Actor Button::GetButtonImage() const
1584 {
1585   DALI_LOG_WARNING("Button::GetButtonImage @DEPRECATED_1_0.50\n");
1586   Actor imageView = Toolkit::ImageView::New( GetUrlForImageVisual( Toolkit::DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL ) );
1587
1588   return imageView;
1589 }
1590
1591 Actor Button::GetSelectedImage() const
1592 {
1593   DALI_LOG_WARNING("Button::GetSelectedImage @DEPRECATED_1_0.50\n");
1594   Actor imageView = Toolkit::ImageView::New( GetUrlForImageVisual( Toolkit::DevelButton::Property::SELECTED_BACKGROUND_VISUAL ) );
1595
1596   return imageView;
1597 }
1598
1599 } // namespace Internal
1600
1601 } // namespace Toolkit
1602
1603 } // namespace Dali