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