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