Merge "Add the logical key to Integration::KeyEvent" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / toggle-button-impl.cpp
1 /*
2  * Copyright (c) 2018 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 "toggle-button-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/images/resource-image.h>
25 #include <dali/devel-api/scripting/scripting.h>
26 #include <dali/public-api/object/property-array.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
31 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
32 #include <dali-toolkit/devel-api/controls/control-devel.h>
33 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
34 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
35 #include <dali-toolkit/public-api/visuals/visual-properties.h>
36 #include <dali-toolkit/public-api/align-enumerations.h>
37 #include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
38 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40
41 #if defined(DEBUG_ENABLED)
42   extern Debug::Filter* gLogButtonFilter;
43 #endif
44
45 namespace Dali
46 {
47
48 namespace Toolkit
49 {
50
51 namespace Internal
52 {
53
54 namespace
55 {
56
57 BaseHandle Create()
58 {
59   return Toolkit::ToggleButton::New();
60 }
61
62 // Properties
63 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToggleButton, Toolkit::Button, Create )
64
65 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "stateVisuals",       ARRAY,     STATE_VISUALS        )
66 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "tooltips",           ARRAY,     TOOLTIPS             )
67 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "currentStateIndex",  INTEGER,   CURRENT_STATE_INDEX  )
68
69 DALI_TYPE_REGISTRATION_END()
70
71 } // unnamed namespace
72
73 Dali::Toolkit::ToggleButton ToggleButton::New()
74 {
75   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::New\n" );
76   // Create the implementation, temporarily owned on stack
77   IntrusivePtr< ToggleButton > internalToggleButton = new ToggleButton();
78
79   // Pass ownership to CustomActor
80   Dali::Toolkit::ToggleButton toggleButton( *internalToggleButton );
81
82   // Second-phase init of the implementation
83   // This can only be done after the CustomActor connection has been made...
84   internalToggleButton->Initialize();
85
86   return toggleButton;
87 }
88
89 ToggleButton::ToggleButton()
90 : Button(),
91   mToggleStates(),
92   mToggleVisuals(),
93   mToggleSelectedVisuals(),
94   mToggleDisabledVisuals(),
95   mToggleDisabledSelectedVisuals(),
96   mToggleTooltips(),
97   mCurrentToggleIndex(0)
98 {
99   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Constructor\n" );
100   SetTogglableButton( false );
101 }
102
103 ToggleButton::~ToggleButton()
104 {
105 }
106
107 void ToggleButton::OnInitialize()
108 {
109   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnInitialize\n" );
110   Button::OnInitialize();
111
112   // Toggle button requires the Leave event.
113   Actor self = Self();
114   self.SetLeaveRequired( true );
115 }
116
117 void ToggleButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
118 {
119   Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
120
121   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::SetProperty index[%d]\n", propertyIndex );
122
123   if ( toggleButton )
124   {
125     ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
126
127     switch ( propertyIndex )
128     {
129       case Toolkit::ToggleButton::Property::STATE_VISUALS:
130       {
131         Property::Array stateArray;
132         if( value.Get( stateArray ) )
133         {
134           toggleButtonImpl.SetToggleStates( stateArray );
135         }
136
137         break;
138       }
139       case Toolkit::ToggleButton::Property::TOOLTIPS:
140       {
141         Property::Array* tipArray = value.GetArray();
142         if( tipArray )
143         {
144           std::vector<std::string> tips;
145           size_t tipsCount = tipArray->Count();
146           tips.resize( tipsCount );
147           for( size_t i = 0; i != tipsCount; ++i )
148           {
149             tipArray->GetElementAt( i ).Get( tips[i] );
150           }
151           toggleButtonImpl.SetToggleTooltips(tips);
152         }
153         break;
154       }
155       default :
156       {
157         break;
158       }
159     } // end of switch
160   }
161 }
162
163 Property::Value ToggleButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
164 {
165   Property::Value value;
166
167   Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
168
169   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::GetProperty index[%d]\n", propertyIndex );
170
171   if ( toggleButton )
172   {
173     ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
174
175     switch ( propertyIndex )
176     {
177       case Toolkit::ToggleButton::Property::STATE_VISUALS:
178       {
179         Property::Array array = toggleButtonImpl.GetToggleStates();
180         value = Property::Value( array );
181         break;
182       }
183       case Toolkit::ToggleButton::Property::TOOLTIPS:
184       {
185         Property::Value value1( Property::ARRAY );
186         Property::Array* tipArray = value1.GetArray();
187
188         if( tipArray )
189         {
190           std::vector<std::string> tips = toggleButtonImpl.GetToggleTooltips();
191           size_t tipsCount( tips.size() );
192           for( size_t i( 0 ); i != tipsCount; ++i )
193           {
194             tipArray->PushBack( tips[i] );
195           }
196         }
197         value = value1;
198         break;
199       }
200       case Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX:
201       {
202         value = static_cast<int>(toggleButtonImpl.mCurrentToggleIndex);
203         break;
204       }
205     } // end of switch
206   }
207
208   return value;
209 }
210
211 void ToggleButton::CreateVisualsForAllStates( const Property::Array& states, std::vector<Toolkit::Visual::Base>& visuals )
212 {
213   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::CreateVisualsForAllStates\n" );
214
215   visuals.clear();
216
217   for ( unsigned int i = 0; i < states.Count(); i++ )
218   {
219     Property::Value value(  states[i] );
220
221     Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
222     Toolkit::Visual::Base stateVisual;
223
224     if ( value.GetType() == Property::MAP )
225     {
226       Property::Map *map = value.GetMap();
227       if( map && !map->Empty() ) // Empty map results in current visual removal.
228       {
229         DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using Map\n" );
230         stateVisual = visualFactory.CreateVisual( *map );
231       }
232     }
233     else if ( value.GetType() ==  Property::STRING )
234     {
235       std::string imageUrl = value.Get<std::string>();
236       DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using image URL\n" );
237       if ( !imageUrl.empty() )
238       {
239         stateVisual = visualFactory.CreateVisual( imageUrl, ImageDimensions() );
240       }
241     }
242
243     if ( stateVisual )
244     {
245       stateVisual.SetDepthIndex( DepthIndex::CONTENT );
246       visuals.push_back( stateVisual );
247     }
248   } // end of for
249   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals mToggleVisuals:%d\n", mToggleVisuals.size() );
250 }
251
252 void ToggleButton::SetToggleStates( const Property::Array& states )
253 { //this should really be generalized to be either string or maps so that any visual can be created.
254   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleStates\n" );
255   if ( !states.Empty() )
256   {
257     mToggleStates.Clear();
258     mToggleStates = states;
259     /* New toggle button index from 0. */
260     mCurrentToggleIndex = 0;
261
262     // Create all visuals, save to mToggleVisuals.
263     CreateVisualsForAllStates( states, mToggleVisuals );
264     CreateVisualsForAllStates( states, mToggleSelectedVisuals );
265     CreateVisualsForAllStates( states, mToggleDisabledVisuals );
266     CreateVisualsForAllStates( states, mToggleDisabledSelectedVisuals );
267
268     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Began to register visual.\n" );
269
270     PrepareVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
271     PrepareVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
272     PrepareVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
273     PrepareVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
274
275     RelayoutRequest();
276   }
277 }
278
279 Property::Array ToggleButton::GetToggleStates() const
280 {
281   return mToggleStates;
282 }
283
284 void ToggleButton::SetToggleTooltips( std::vector<std::string>& tips )
285 {
286   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleTooltips\n" );
287   if ( !tips.empty() )
288   {
289     mToggleTooltips.clear();
290     mToggleTooltips.swap( tips );
291   }
292
293   if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
294   {
295     Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
296   }
297
298   RelayoutRequest();
299 }
300
301 const std::vector<std::string>& ToggleButton::GetToggleTooltips() const
302 {
303   return mToggleTooltips;
304 }
305
306 void ToggleButton::PrepareVisual(Property::Index index, Toolkit::Visual::Base& visual)
307 {
308   bool enabled = false; // Disabled by default
309
310   // Unregister the visual with the given index if registered previously
311   if( DevelControl::GetVisual( *this, index ) )
312   {
313     // Check whether it was enabled to ensure we do the same with the new visual we're registering
314     enabled = DevelControl::IsVisualEnabled( *this, index );
315     DevelControl::UnregisterVisual( *this, index );
316   }
317
318   DevelControl::RegisterVisual( *this, index, visual, enabled );
319 }
320
321 void ToggleButton::RelayoutVisual( Property::Index index, const Vector2& size )
322 {
323   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, index );
324   if ( visual )
325   {
326     Size visualSize = Size::ZERO;
327     Vector2 visualPosition = Vector2::ZERO;
328
329     visual.GetNaturalSize( visualSize );
330
331     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height );
332     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual position to(%f,%f)\n", visualPosition.x, visualPosition.y );
333
334     Property::Map visualTransform;
335     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
336                    .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
337                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
338                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
339                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::CENTER )
340                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::CENTER );
341
342     visual.SetTransformAndSize( visualTransform, size );
343   }
344 }
345
346 void ToggleButton::OnRelayout( const Vector2& size, RelayoutContainer& container )
347 {
348   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout targetSize(%f,%f) ptr(%p)\n", size.width, size.height, this );
349
350   RelayoutVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, size );
351   RelayoutVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, size );
352   RelayoutVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, size );
353   RelayoutVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, size );
354 }
355
356 void ToggleButton::OnPressed()
357 {
358   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnPressed\n" );
359   // State index will add 1 only when button is pressed.
360   mCurrentToggleIndex = ( mCurrentToggleIndex + 1 ) % mToggleVisuals.size();
361
362   // Both create SelectedVisual and UnselectedVisual
363   PrepareVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
364   PrepareVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
365   PrepareVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
366   PrepareVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
367
368   //Need to check mCurrentToggleIndex, it must less than the size of mToggleTooltips.
369   if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
370   {
371     Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
372   }
373
374   RelayoutRequest();
375 }
376
377 } // namespace Internal
378
379 } // namespace Toolkit
380
381 } // namespace Dali