Merge "Stop resetting transform values to default in OnRelayout & OnSizeSet" into...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / progress-bar / progress-bar-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <sstream>
24 #include <algorithm>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <dali/public-api/size-negotiation/relayout-container.h>
27 #include <dali/public-api/math/math-utils.h>
28 #include <dali-toolkit/devel-api/align-enums.h>
29 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
30 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
31 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
32 #include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
33 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
34 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
35
36 #include <dali/integration-api/debug.h>
37
38 namespace Dali
39 {
40
41 namespace Toolkit
42 {
43
44 namespace Internal
45 {
46
47 namespace // Unnamed namespace
48 {
49
50 BaseHandle Create()
51 {
52   return Dali::Toolkit::ProgressBar::New();
53 }
54
55 // Setup properties, signals and actions using the type-registry.
56 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ProgressBar, Toolkit::Control, Create )
57
58 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressValue",                     FLOAT,    PROGRESS_VALUE                   )
59 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "secondaryProgressValue",            FLOAT,    SECONDARY_PROGRESS_VALUE         )
60 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminate",                     BOOLEAN,  INDETERMINATE                    )
61 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "trackVisual",                       MAP,      TRACK_VISUAL                     )
62 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressVisual",                    MAP,      PROGRESS_VISUAL                  )
63 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "secondaryProgressVisual",           MAP,      SECONDARY_PROGRESS_VISUAL        )
64 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminateVisual",               MAP,      INDETERMINATE_VISUAL             )
65 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminateVisualAnimation",      ARRAY,    INDETERMINATE_VISUAL_ANIMATION   )
66 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "labelVisual",                       MAP,      LABEL_VISUAL                     )
67 DALI_SIGNAL_REGISTRATION(   Toolkit, ProgressBar, "valueChanged",                      SIGNAL_VALUE_CHANGED                       )
68
69 DALI_TYPE_REGISTRATION_END()
70
71 struct ProgressDepthIndex
72 {
73   // Enum to make sure the visual order
74   enum
75   {
76     TRACK_VISUAL,
77     SECONDARY_PROGRESS_VISUAL,
78     PROGRESS_VISUAL,
79     LABEL_VISUAL,
80     INDETERMINATE_VISUAL
81   };
82 };
83
84 float DEFAULT_VALUE = 0.0f;
85 float DEFAULT_LOWER_BOUND = 0.0f;
86 float DEFAULT_UPPER_BOUND = 1.0f;
87 float DEFAULT_FONT_SIZE = 12.0f;
88
89 } // Unnamed namespace
90
91 ///////////////////////////////////////////////////////////////////////////////////////////////////
92 // ProgressBar
93 ///////////////////////////////////////////////////////////////////////////////////////////////////
94
95 Dali::Toolkit::ProgressBar ProgressBar::New()
96 {
97   // Create the implementation
98   ProgressBarPtr progressBar( new ProgressBar() );
99
100   // Pass ownership to CustomActor via derived handle
101   Dali::Toolkit::ProgressBar handle( *progressBar );
102
103   // Second-phase init of the implementation
104   // This can only be done after the CustomActor connection has been made...
105   progressBar->Initialize();
106
107   return handle;
108 }
109
110 ProgressBar::ProgressBar()
111 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
112   mProgressValue( DEFAULT_VALUE ),
113   mSecondaryProgressValue( DEFAULT_VALUE ),
114   mIndeterminate( false )
115 {
116 }
117
118 ProgressBar::~ProgressBar()
119 {
120 }
121
122 void ProgressBar::OnInitialize()
123 {
124 }
125
126 void ProgressBar::OnRelayout( const Vector2& size, RelayoutContainer& container )
127 {
128
129   Vector2 trackSize( size );
130   mDomain = CalcDomain( size );
131
132   trackSize.width = std::max( 0.0f, size.width ); // Ensure we don't go negative
133
134   Toolkit::Visual::Base trackVisual = GetVisual( Toolkit::ProgressBar::Property::TRACK_VISUAL );
135   Toolkit::Visual::Base secondProgressVisual = GetVisual( Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL );
136   Toolkit::Visual::Base progressVisual = GetVisual( Toolkit::ProgressBar::Property::PROGRESS_VISUAL );
137   Toolkit::Visual::Base labelVisual = GetVisual( Toolkit::ProgressBar::Property::LABEL_VISUAL );
138   Toolkit::Visual::Base indeterminateVisual = GetVisual( Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL );
139
140   if( trackVisual )
141   {
142     Property::Map visualTransform;
143
144     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, trackSize )
145                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );  // Use Absolute size
146     trackVisual.SetTransformAndSize( visualTransform, trackSize );
147   }
148
149   if( secondProgressVisual )
150   {
151     Property::Map visualTransform;
152
153     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, Vector2( mDomain.from.x + mSecondaryProgressValue * ( mDomain.to.x - mDomain.from.x ), trackSize.height  ) )
154                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) )  // Use Absolute size
155                    .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
156                    .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
157     secondProgressVisual.SetTransformAndSize( visualTransform, trackSize );
158   }
159
160   if( progressVisual )
161   {
162     Property::Map visualTransform;
163
164     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, Vector2( mDomain.from.x + mProgressValue * ( mDomain.to.x - mDomain.from.x ), trackSize.height ) )
165                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) )  // Use Absolute size
166                    .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
167                    .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
168     progressVisual.SetTransformAndSize( visualTransform, trackSize );
169   }
170
171   if( labelVisual )
172   {
173     Property::Map visualTransform;
174
175     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, trackSize )
176                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );  // Use Absolute size
177
178     labelVisual.SetTransformAndSize( visualTransform, trackSize );
179   }
180
181   if( indeterminateVisual )
182   {
183     Property::Map visualTransform;
184
185     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, trackSize )
186                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_SIZE_MODE, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );  // Use Absolute size
187     indeterminateVisual.SetTransformAndSize( visualTransform, trackSize );
188   }
189
190 }
191
192 Vector3 ProgressBar::GetNaturalSize()
193 {
194   // Return the bigger size after comparing trackVisual naturalSize and labelVisual naturalSize
195   Toolkit::Visual::Base trackVisual =  GetVisual( Toolkit::ProgressBar::Property::TRACK_VISUAL );
196   Toolkit::Visual::Base labelVisual =  GetVisual( Toolkit::ProgressBar::Property::LABEL_VISUAL );
197
198   Size trackSize;
199   Size labelSize;
200
201   if ( trackVisual )
202   {
203     trackVisual.GetNaturalSize( trackSize );
204   }
205   if ( labelVisual )
206   {
207     labelVisual.GetNaturalSize( labelSize );
208   }
209
210   Vector3 naturalSize;
211   naturalSize.width = ( trackSize.width > labelSize.width ) ? trackSize.width: labelSize.width;
212   naturalSize.height = ( trackSize.height > labelSize.height ) ? trackSize.height: labelSize.height;
213
214   return naturalSize;
215 }
216
217 ProgressBar::Domain ProgressBar::CalcDomain( const Vector2& currentSize )
218 {
219    return Domain( Vector2( 0.0f, 0.0f ), currentSize );
220 }
221
222 Toolkit::ProgressBar::ValueChangedSignalType& ProgressBar::ValueChangedSignal()
223 {
224   return mValueChangedSignal;
225 }
226
227 void ProgressBar::SetProgressValue( float value )
228 {
229   // update the progress bar value (taking float precision errors into account)
230   // TODO : it seems 0.0f cannot into this statement.
231   if( ( mProgressValue != value ) &&
232       ( ( value >= DEFAULT_LOWER_BOUND ) || ( Equals( value, DEFAULT_LOWER_BOUND ) ) ) &&
233       ( ( value <= DEFAULT_UPPER_BOUND ) || ( Equals( value, DEFAULT_UPPER_BOUND ) ) ) )
234   {
235     mProgressValue = Clamp( value, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND );
236
237     Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() );
238     mValueChangedSignal.Emit( self, mProgressValue, mSecondaryProgressValue );
239     RelayoutRequest();
240   }
241 }
242
243 float ProgressBar::GetProgressValue() const
244 {
245   return mProgressValue;
246 }
247
248 void ProgressBar::SetSecondaryProgressValue( float value )
249 {
250   // update the progress bar value (taking float precision errors into account)
251   // TODO : it seems 0.0f cannot into this statement.
252   if( ( mSecondaryProgressValue != value ) &&
253       ( ( value >= DEFAULT_LOWER_BOUND ) || ( Equals( value, DEFAULT_LOWER_BOUND ) ) ) &&
254       ( ( value <= DEFAULT_UPPER_BOUND ) || ( Equals( value, DEFAULT_UPPER_BOUND ) ) ) )
255   {
256     mSecondaryProgressValue = Clamp( value, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND );
257
258     Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() );
259     mValueChangedSignal.Emit( self, mProgressValue, mSecondaryProgressValue );
260
261     RelayoutRequest();
262   }
263 }
264
265 float ProgressBar::GetSecondaryProgressValue() const
266 {
267   return mSecondaryProgressValue;
268 }
269
270 void ProgressBar::SetIndeterminate( bool value )
271 {
272   mIndeterminate = value;
273   EnableVisual( Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL, mIndeterminate );
274
275   if( mIndeterminate )
276   {
277     RelayoutRequest();
278     if( mIndeterminateVisualTransition )
279     {
280       PlayIndeterminateVisualTransition();
281     }
282   }
283   else
284   {
285     if( mIndeterminateVisualAni )
286     {
287       mIndeterminateVisualAni.Stop();
288     }
289   }
290 }
291
292 bool ProgressBar::GetIndeterminate() const
293 {
294   return mIndeterminate;
295 }
296
297 void ProgressBar::SetIndeterminateVisualTransition( Toolkit::TransitionData transition )
298 {
299   mIndeterminateVisualTransition = transition;
300   if( mIndeterminate )
301   {
302     PlayIndeterminateVisualTransition();
303   }
304 }
305
306 void ProgressBar::PlayIndeterminateVisualTransition()
307 {
308   if( mIndeterminateVisualAni )
309   {
310     mIndeterminateVisualAni.Stop();
311     mIndeterminateVisualAni.Clear();
312   }
313
314   mIndeterminateVisualAni = CreateTransition( mIndeterminateVisualTransition );
315
316   if( mIndeterminate && mIndeterminateVisualAni )
317   {
318     mIndeterminateVisualAni.SetLooping(true);
319     mIndeterminateVisualAni.Play();
320   }
321 }
322
323 Toolkit::TransitionData ProgressBar::ConvertPropertyToTransition( const Property::Value& value )
324 {
325   Toolkit::TransitionData transitionData;
326
327   if( value.GetType() == Property::ARRAY )
328   {
329     transitionData = Toolkit::TransitionData::New( *value.GetArray() );
330   }
331   else if( value.GetType() == Property::MAP )
332   {
333     transitionData = Toolkit::TransitionData::New( *value.GetMap() );
334   }
335
336   return transitionData;
337 }
338
339 /**
340  * Create Visual for given index from a property map or url.
341  * 1) Check if value passed in is a url and create visual
342  * 2) Create visual from map if step (1) is false
343  * 3) Register visual with control with false for enable flag.
344  * 4) Unregister visual if empty map was provided. This is the method to remove a visual
345  */
346
347 void ProgressBar::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const float visualDepth )
348 {
349   Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
350   Toolkit::Visual::Base progressVisual;
351
352   std::string imageUrl;
353   if( value.Get( imageUrl ) )
354   {
355     if ( !imageUrl.empty() )
356     {
357       progressVisual = visualFactory.CreateVisual(  imageUrl, ImageDimensions()  );
358     }
359   }
360   else // Does this code make text-visual can be accepted as visual?
361   {
362     // if its not a string then get a Property::Map from the property if possible.
363     Property::Map *map = value.GetMap();
364     if( map && !map->Empty()  ) // Empty map results in current visual removal.
365     {
366       progressVisual = visualFactory.CreateVisual( *map );
367     }
368   }
369
370   if ( progressVisual )
371   {
372     progressVisual.SetDepthIndex( visualDepth );
373     if( index == Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL )
374     {
375       RegisterVisual( index, progressVisual, mIndeterminate );
376     }
377     else
378     {
379       RegisterVisual( index, progressVisual, true );
380     }
381   }
382   else
383   {
384     UnregisterVisual( index );
385   }
386 }
387
388 bool ProgressBar::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
389 {
390   bool success = false;
391   Toolkit::Visual::Base visual = GetVisual( visualIndex );
392
393   if ( visual )
394   {
395     visual.CreatePropertyMap( retreivedMap );
396     success = true;
397   }
398
399   return success;
400 }
401
402 // Static class method to support script connecting signals
403 bool ProgressBar::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
404 {
405   Dali::BaseHandle handle( object );
406
407   bool connected = true;
408   Toolkit::ProgressBar ProgressBar = Toolkit::ProgressBar::DownCast( handle );
409
410   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
411   {
412     ProgressBar.ValueChangedSignal().Connect( tracker, functor );
413   }
414   else
415   {
416     // signalName does not match any signal
417     connected = false;
418   }
419
420   return connected;
421 }
422
423 void ProgressBar::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
424 {
425   Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
426
427   if ( progressBar )
428   {
429     ProgressBar& progressBarImpl( GetImpl( progressBar ) );
430
431     switch ( propertyIndex )
432     {
433       case Toolkit::ProgressBar::Property::TRACK_VISUAL:
434       {
435         progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::TRACK_VISUAL );
436         break;
437       }
438
439       case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL:
440       {
441         progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::SECONDARY_PROGRESS_VISUAL );
442         break;
443       }
444
445       case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
446       {
447         progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::PROGRESS_VISUAL );
448         break;
449       }
450
451       case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL:
452       {
453         progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::INDETERMINATE_VISUAL );
454         break;
455       }
456
457       case Toolkit::ProgressBar::Property::LABEL_VISUAL:
458       {
459         Property::Map map;
460         std::string textString;
461
462         if ( value.Get( textString ) )
463         {
464           // set new text string as TEXT property
465           Property::Map newTextMap;
466           Toolkit::Visual::Base label = progressBarImpl.GetVisual( Toolkit::ProgressBar::Property::LABEL_VISUAL );
467
468           if( label )
469           {
470             label.CreatePropertyMap( map );
471           }
472
473           // if LABEL_VISUAL doesn't set before, add Visual property "TYPE" to create new text Visual
474           if( map.Empty() )
475           {
476             newTextMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::TEXT );
477             newTextMap.Add( Toolkit::TextVisual::Property::POINT_SIZE, DEFAULT_FONT_SIZE );
478           }
479           newTextMap.Add( Toolkit::TextVisual::Property::TEXT, textString );
480
481           map.Merge( newTextMap );
482         }
483         else
484         {
485           value.Get( map );
486         }
487
488         if( !map.Empty() )
489         {
490           progressBarImpl.CreateVisualsForComponent( propertyIndex, map, ProgressDepthIndex::LABEL_VISUAL );
491         }
492         break;
493       }
494
495       case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
496       {
497         progressBarImpl.SetProgressValue( value.Get< float >() );
498         break;
499       }
500
501       case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VALUE:
502       {
503         progressBarImpl.SetSecondaryProgressValue( value.Get< float >() );
504         break;
505       }
506
507       case Toolkit::ProgressBar::Property::INDETERMINATE:
508       {
509         progressBarImpl.SetIndeterminate( value.Get< bool >() );
510         break;
511       }
512
513       case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION:
514       {
515         progressBarImpl.SetIndeterminateVisualTransition( progressBarImpl.ConvertPropertyToTransition( value ) );
516         break;
517       }
518     }
519   }
520 }
521
522 Property::Value ProgressBar::GetProperty( BaseObject* object, Property::Index propertyIndex )
523 {
524   Property::Value value;
525
526   Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
527
528   if ( progressBar )
529   {
530     ProgressBar& progressBarImpl( GetImpl( progressBar ) );
531
532     switch ( propertyIndex )
533     {
534       case Toolkit::ProgressBar::Property::TRACK_VISUAL:
535       case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
536       case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL:
537       case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL:
538       case Toolkit::ProgressBar::Property::LABEL_VISUAL:
539       {
540         Property::Map visualProperty;
541         if ( progressBarImpl.GetPropertyMapForVisual( propertyIndex, visualProperty ) )
542         {
543           value = visualProperty;
544         }
545         break;
546       }
547
548       case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
549       {
550         value = progressBarImpl.GetProgressValue();
551         break;
552       }
553
554       case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VALUE:
555       {
556         value = progressBarImpl.GetSecondaryProgressValue();
557         break;
558       }
559
560       case Toolkit::ProgressBar::Property::INDETERMINATE:
561       {
562         value = progressBarImpl.GetIndeterminate();
563         break;
564       }
565
566       case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION:
567       {
568         //TODO: Return INDETERMINATE_VISUAL_TRANSITION;
569       }
570     }
571   }
572
573   return value;
574 }
575
576 void ProgressBar::OnStageConnection( int depth )
577 {
578   // Chain up first (ensures visuals are ready to draw)
579   Control::OnStageConnection( depth );
580
581   if( mIndeterminate )
582   {
583     PlayIndeterminateVisualTransition();
584   }
585 }
586
587 } // namespace Internal
588
589 } // namespace Toolkit
590
591 } // namespace Dali