[dali_1.2.5] Merge branch 'devel/master'
[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
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Internal
36 {
37
38 namespace // Unnamed namespace
39 {
40
41 BaseHandle Create()
42 {
43   return Dali::Toolkit::ProgressBar::New();
44 }
45
46 // Setup properties, signals and actions using the type-registry.
47 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ProgressBar, Toolkit::Control, Create )
48
49 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressValue",          FLOAT,    PROGRESS_VALUE         )
50 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "trackVisual",            MAP,      TRACK_VISUAL           )
51 DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressVisual",         MAP,      PROGRESS_VISUAL        )
52 DALI_SIGNAL_REGISTRATION(   Toolkit, ProgressBar, "valueChanged",                     SIGNAL_VALUE_CHANGED   )
53
54 DALI_TYPE_REGISTRATION_END()
55
56 const char* SKINNED_TRACK_VISUAL = DALI_IMAGE_DIR "slider-skin.9.png";
57 const char* SKINNED_PROGRESS_VISUAL = DALI_IMAGE_DIR "slider-skin-progress.9.png";
58
59 float DEFAULT_VALUE = 0.0f;
60 float DEFAULT_LOWER_BOUND = 0.0f;
61 float DEFAULT_UPPER_BOUND = 1.0f;
62 float DEFAULT_PADDING = 24.0f;
63
64 } // Unnamed namespace
65
66 ///////////////////////////////////////////////////////////////////////////////////////////////////
67 // ProgressBar
68 ///////////////////////////////////////////////////////////////////////////////////////////////////
69
70 Dali::Toolkit::ProgressBar ProgressBar::New()
71 {
72   // Create the implementation
73   ProgressBarPtr progressBar( new ProgressBar() );
74
75   // Pass ownership to CustomActor via derived handle
76   Dali::Toolkit::ProgressBar handle( *progressBar );
77
78   // Second-phase init of the implementation
79   // This can only be done after the CustomActor connection has been made...
80   progressBar->Initialize();
81
82   return handle;
83 }
84
85 ProgressBar::ProgressBar()
86 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
87   mTrackVisual(""),
88   mProgressVisual(""),
89   mTrackMap(),
90   mTrackVisualSize(),
91   mProgressVisualSize(),
92   mValue( DEFAULT_VALUE )
93 {
94 }
95
96 ProgressBar::~ProgressBar()
97 {
98 }
99
100 void ProgressBar::OnInitialize()
101 {
102   // Setup
103   CreateChildren();
104
105   // Properties
106   SetTrackVisual( SKINNED_TRACK_VISUAL );
107   SetProgressVisual( SKINNED_PROGRESS_VISUAL );
108
109   DisplayValue( mValue, false );       // Run this last to display the correct value
110 }
111
112 void ProgressBar::OnRelayout( const Vector2& size, RelayoutContainer& container )
113 {
114   Vector2 trackSize( size );
115   trackSize.width = std::max( 0.0f, size.width - DEFAULT_PADDING ); // Ensure we don't go negative
116
117   // Track
118   if( mTrack )
119   {
120     container.Add( mTrack, trackSize );
121
122     // mValueTextLabel will have its relayout method called automatically as it's a child of mTrack,
123     // which is added to the container
124   }
125
126   // Progress bar
127   if( mProgress )
128   {
129     mDomain = CalcDomain( trackSize );
130
131     Vector2 progressSize( trackSize );
132
133     // If no progress, then we do not want a n-patch image shown incorrectly
134     progressSize.width = std::max( mProgressVisualSize.width, mDomain.from.x + mValue * ( mDomain.to.x - mDomain.from.x ) );
135     progressSize.width = std::min( progressSize.width, trackSize.width ); // We should not exceed given size
136
137     container.Add( mProgress, progressSize );
138   }
139 }
140
141 Vector3 ProgressBar::GetNaturalSize()
142 {
143   // Return the maximum width/height combinations of our visuals
144
145   Vector3 naturalSize;
146   naturalSize.width = std::max( mTrackVisualSize.width, mProgressVisualSize.width );
147   naturalSize.height = std::max( mTrackVisualSize.height, mProgressVisualSize.height );
148   return naturalSize;
149 }
150
151 ProgressBar::Domain ProgressBar::CalcDomain( const Vector2& currentSize )
152 {
153    return Domain( Vector2( 0.0f, 0.0f ), currentSize );
154 }
155
156 void ProgressBar::DisplayValue( float value, bool raiseSignals )
157 {
158   // Signals
159   if( raiseSignals )
160   {
161     Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() );
162     mValueChangedSignal.Emit( self, value );
163   }
164
165   // Change the value of the text label
166   if( mValueTextLabel )
167   {
168     std::stringstream ss;
169     ss.precision( 0 );
170     ss << std::fixed << ( value * 100 ) << "%";
171
172     std::string label = mValueTextLabel.GetProperty<std::string>( Toolkit::TextLabel::Property::TEXT );
173     if( label.compare(ss.str()) )
174     {
175       mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
176     }
177   }
178 }
179
180 Toolkit::ImageView ProgressBar::CreateTrack()
181 {
182   Toolkit::ImageView track = Toolkit::ImageView::New();
183   track.SetParentOrigin( ParentOrigin::CENTER );
184   track.SetAnchorPoint( AnchorPoint::CENTER );
185   track.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::ALL_DIMENSIONS );
186
187   return track;
188 }
189
190 void ProgressBar::SetTrackVisual( const std::string& filename )
191 {
192   if( mTrack && filename.size() > 0 )
193   {
194     mTrack.SetImage( filename );
195     mTrackVisual = filename;
196     mTrackVisualSize = Vector2::ZERO;
197     RelayoutRequest();
198   }
199 }
200
201 void ProgressBar::SetTrackVisual( Property::Map map )
202 {
203   bool relayoutRequired = false;
204
205   Property::Value* imageValue = map.Find( "url" );
206   if( imageValue )
207   {
208     mTrackVisual.clear();
209     std::string filename;
210     if( imageValue->Get( filename ) )
211     {
212       if( mTrack && ( filename.size() > 0 ) )
213       {
214         mTrack.SetImage( filename );
215         mTrackMap = map;
216         relayoutRequired = true;
217       }
218     }
219   }
220
221   Property::Value* sizeValue = map.Find( "size" );
222   if( sizeValue )
223   {
224     Vector2 size;
225     if( sizeValue->Get( size ) )
226     {
227       mTrackVisualSize = size;
228       relayoutRequired = true;
229     }
230   }
231
232   // Visual and/or visual size changed so we need to relayout
233   if( relayoutRequired )
234   {
235     RelayoutRequest();
236   }
237 }
238
239 std::string ProgressBar::GetTrackVisual()
240 {
241   return mTrackVisual;
242 }
243
244 Toolkit::ImageView ProgressBar::CreateProgress()
245 {
246   Toolkit::ImageView progress = Toolkit::ImageView::New();
247   progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
248   progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
249   progress.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::ALL_DIMENSIONS );
250
251   return progress;
252 }
253
254 void ProgressBar::SetProgressVisual( const std::string& filename )
255 {
256   if( mProgress && ( filename.size() > 0 ) )
257   {
258     mProgress.SetImage( filename );
259     mProgressVisual = filename;
260     mProgressVisualSize = Vector2::ZERO;
261     RelayoutRequest();
262   }
263 }
264
265 void ProgressBar::SetProgressVisual( Property::Map map )
266 {
267   bool relayoutRequired = false;
268
269   Property::Value* imageValue = map.Find( "url" );
270   if( imageValue )
271   {
272     mProgressVisual.clear();
273     std::string filename;
274     if( imageValue->Get( filename ) )
275     {
276       if( mProgress && ( filename.size() > 0 ) )
277       {
278         mProgress.SetImage( filename );
279         mProgressMap = map;
280         relayoutRequired = true;
281       }
282     }
283   }
284
285   Property::Value* sizeValue = map.Find( "size" );
286   if( sizeValue )
287   {
288     Vector2 size;
289     if( sizeValue->Get( size ) )
290     {
291       mProgressVisualSize = size;
292       relayoutRequired = true;
293     }
294   }
295
296   // Visual and/or visual size changed so we need to relayout
297   if( relayoutRequired )
298   {
299     RelayoutRequest();
300   }
301 }
302
303 std::string ProgressBar::GetProgressVisual()
304 {
305   return mProgressVisual;
306 }
307
308 Toolkit::ProgressBar::ValueChangedSignalType& ProgressBar::ValueChangedSignal()
309 {
310   return mValueChangedSignal;
311 }
312
313 void ProgressBar::CreateChildren()
314 {
315   Actor self = Self();
316
317   // Track
318   mTrack = CreateTrack();
319   self.Add( mTrack ); // Needs to be a direct child as we want to manipulate its size
320
321   // Progress bar
322   mProgress = CreateProgress();
323   self.Add( mProgress ); // Needs to be a direct child as we want to manipulate its size
324
325   // Value Text
326   mValueTextLabel = Toolkit::TextLabel::New();
327   mValueTextLabel.SetName( "ProgressBarValueTextLabel" );
328   mValueTextLabel.SetStyleName( "ProgressBarValueTextLabel" );
329   mValueTextLabel.SetParentOrigin( ParentOrigin::CENTER );
330   mValueTextLabel.SetAnchorPoint( AnchorPoint::CENTER );
331   mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
332   mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
333   mTrack.Add( mValueTextLabel ); // Add to mTrack and let it automatically set its size
334 }
335
336 void ProgressBar::SetProgressValue( float value )
337 {
338   // update the progress bar value (taking float precision errors into account)
339   if( ( mValue != value ) &&
340       ( ( value >= DEFAULT_LOWER_BOUND ) || ( Equals( value, DEFAULT_LOWER_BOUND ) ) ) &&
341       ( ( value <= DEFAULT_UPPER_BOUND ) || ( Equals( value, DEFAULT_UPPER_BOUND ) ) ) )
342   {
343     mValue = Clamp( value, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND );
344     DisplayValue( mValue, true );
345     RelayoutRequest();
346   }
347 }
348
349 float ProgressBar::GetProgressValue() const
350 {
351   return mValue;
352 }
353
354 // Static class method to support script connecting signals
355 bool ProgressBar::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
356 {
357   Dali::BaseHandle handle( object );
358
359   bool connected = true;
360   Toolkit::ProgressBar ProgressBar = Toolkit::ProgressBar::DownCast( handle );
361
362   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
363   {
364     ProgressBar.ValueChangedSignal().Connect( tracker, functor );
365   }
366   else
367   {
368     // signalName does not match any signal
369     connected = false;
370   }
371
372   return connected;
373 }
374
375 void ProgressBar::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
376 {
377   Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
378
379   if ( progressBar )
380   {
381     ProgressBar& progressBarImpl( GetImpl( progressBar ) );
382
383     switch ( propertyIndex )
384     {
385       case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
386       {
387         progressBarImpl.SetProgressValue( value.Get< float >() );
388         break;
389       }
390
391       case Toolkit::ProgressBar::Property::TRACK_VISUAL:
392       {
393         Property::Map map;
394         if( value.Get( map ) )
395         {
396           progressBarImpl.SetTrackVisual( map );
397         }
398         break;
399       }
400
401       case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
402       {
403         Property::Map map;
404         if( value.Get( map ) )
405         {
406           progressBarImpl.SetProgressVisual( map );
407         }
408         break;
409       }
410     }
411   }
412 }
413
414 Property::Value ProgressBar::GetProperty( BaseObject* object, Property::Index propertyIndex )
415 {
416   Property::Value value;
417
418   Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
419
420   if ( progressBar )
421   {
422     ProgressBar& progressBarImpl( GetImpl( progressBar ) );
423
424     switch ( propertyIndex )
425     {
426       case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
427       {
428         value = progressBarImpl.GetProgressValue();
429         break;
430       }
431
432       case Toolkit::ProgressBar::Property::TRACK_VISUAL:
433       {
434         if( !progressBarImpl.mTrackVisual.empty() )
435         {
436           value = progressBarImpl.GetTrackVisual();
437         }
438         else if( !progressBarImpl.mTrackMap.Empty() )
439         {
440           value = progressBarImpl.mTrackMap;
441         }
442         break;
443       }
444
445       case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
446       {
447         if( !progressBarImpl.mProgressVisual.empty() )
448         {
449           value = progressBarImpl.GetProgressVisual();
450         }
451         else if( !progressBarImpl.mProgressMap.Empty() )
452         {
453           value = progressBarImpl.mProgressMap;
454         }
455         break;
456       }
457     }
458   }
459
460   return value;
461 }
462
463 } // namespace Internal
464
465 } // namespace Toolkit
466
467 } // namespace Dali