719a0fb26462d60a4e7f1127822867ca74307c76
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-base-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 "visual-base-impl.h"
20
21 // EXTERNAL HEADER
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/devel-api/object/handle-devel.h>
24 #include <dali/integration-api/debug.h>
25
26 //INTERNAL HEARDER
27 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
28 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
29 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
30
31 namespace
32 {
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VISUAL_BASE" );
35 #endif
36 }
37
38 namespace Dali
39 {
40
41 namespace Toolkit
42 {
43
44 namespace Internal
45 {
46
47 Visual::Base::Base( VisualFactoryCache& factoryCache )
48 : mImpl( new Impl() ),
49   mFactoryCache( factoryCache )
50 {
51 }
52
53 Visual::Base::~Base()
54 {
55   delete mImpl;
56 }
57
58 void Visual::Base::SetCustomShader( const Property::Map& shaderMap )
59 {
60   if( mImpl->mCustomShader )
61   {
62     mImpl->mCustomShader->SetPropertyMap( shaderMap );
63   }
64   else
65   {
66     mImpl->mCustomShader = new Impl::CustomShader( shaderMap );
67   }
68 }
69
70 void Visual::Base::SetProperties( const Property::Map& propertyMap )
71 {
72   for( size_t i = 0; i < propertyMap.Count(); ++i )
73   {
74     const KeyValuePair& pair = propertyMap.GetKeyValue( i );
75     const Property::Key& key = pair.first;
76     const Property::Value& value = pair.second;
77
78     Property::Key matchKey = key;
79     if( matchKey.type == Property::Key::STRING )
80     {
81       if( matchKey == CUSTOM_SHADER )
82       {
83         matchKey = Property::Key( DevelVisual::Property::SHADER );
84       }
85       else if( matchKey == TRANSFORM )
86       {
87         matchKey = Property::Key( DevelVisual::Property::TRANSFORM );
88       }
89       else if( matchKey == PREMULTIPLIED_ALPHA )
90       {
91         matchKey = Property::Key( DevelVisual::Property::PREMULTIPLIED_ALPHA );
92       }
93       else if( matchKey == MIX_COLOR )
94       {
95         matchKey = Property::Key( DevelVisual::Property::MIX_COLOR );
96       }
97     }
98
99     switch( matchKey.indexKey )
100     {
101       case DevelVisual::Property::SHADER:
102       {
103         Property::Map shaderMap;
104         if( value.Get( shaderMap ) )
105         {
106           SetCustomShader( shaderMap );
107         }
108         break;
109       }
110
111       case DevelVisual::Property::TRANSFORM:
112       {
113         Property::Map map;
114         if( value.Get( map ) )
115         {
116           mImpl->mTransform.SetPropertyMap( map );
117         }
118         break;
119       }
120
121       case DevelVisual::Property::PREMULTIPLIED_ALPHA:
122       {
123         bool premultipliedAlpha = false;
124         if( value.Get( premultipliedAlpha ) )
125         {
126           EnablePreMultipliedAlpha( premultipliedAlpha );
127         }
128         break;
129       }
130
131       case DevelVisual::Property::MIX_COLOR:
132       {
133         Vector4 mixColor;
134         if( value.Get( mixColor ) )
135         {
136           SetMixColor( mixColor );
137         }
138         break;
139       }
140     }
141   }
142
143   DoSetProperties( propertyMap );
144 }
145
146 void Visual::Base::SetTransformAndSize( const Property::Map& transform, Size controlSize )
147 {
148   mImpl->mControlSize = controlSize;
149   mImpl->mTransform.SetPropertyMap( transform );
150
151 #if defined(DEBUG_ENABLED)
152   std::ostringstream oss;
153   oss << transform;
154   DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::SetTransformAndSize(%s) - [\e[1;32mtransform: %s  controlSize: (%3.1f, %3.1f)]\e[0m\n",
155                  GetName().c_str(), oss.str().c_str(), controlSize.x, controlSize.y );
156 #endif
157
158   OnSetTransform();
159 }
160
161 void Visual::Base::SetName( const std::string& name )
162 {
163   mImpl->mName = name;
164 }
165
166 const std::string& Visual::Base::GetName()
167 {
168   return mImpl->mName;
169 }
170
171 float Visual::Base::GetHeightForWidth( float width )
172 {
173   float aspectCorrectedHeight = 0.f;
174   Vector2 naturalSize;
175   GetNaturalSize( naturalSize );
176   if( naturalSize.width )
177   {
178     aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
179   }
180   return aspectCorrectedHeight;
181 }
182
183 float Visual::Base::GetWidthForHeight( float height )
184 {
185   float aspectCorrectedWidth = 0.f;
186   Vector2 naturalSize;
187   GetNaturalSize( naturalSize );
188   if( naturalSize.height > 0.0f )
189   {
190     aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
191   }
192   return aspectCorrectedWidth;
193 }
194
195 void Visual::Base::GetNaturalSize( Vector2& naturalSize )
196 {
197   naturalSize = Vector2::ZERO;
198 }
199
200 void Visual::Base::SetDepthIndex( float index )
201 {
202   mImpl->mDepthIndex = index;
203   if( mImpl->mRenderer )
204   {
205     mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
206   }
207 }
208
209 float Visual::Base::GetDepthIndex() const
210 {
211   return mImpl->mDepthIndex;
212 }
213
214 void Visual::Base::SetOnStage( Actor& actor )
215 {
216   if( !IsOnStage() )
217   {
218     // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
219     // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
220     DoSetOnStage( actor );
221
222     if( mImpl->mRenderer )
223     {
224       RegisterMixColor();
225
226       mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
227       mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
228       mImpl->mFlags |= Impl::IS_ON_STAGE; // Only sets the flag if renderer exists
229     }
230   }
231 }
232
233 void Visual::Base::SetOffStage( Actor& actor )
234 {
235   if( IsOnStage() )
236   {
237     DoSetOffStage( actor );
238     mImpl->mMixColorIndex = Property::INVALID_INDEX;
239     mImpl->mFlags &= ~Impl::IS_ON_STAGE;
240   }
241 }
242
243 void Visual::Base::CreatePropertyMap( Property::Map& map ) const
244 {
245   DoCreatePropertyMap( map );
246
247   if( mImpl->mCustomShader )
248   {
249     mImpl->mCustomShader->CreatePropertyMap( map );
250   }
251
252   Property::Map transform;
253   mImpl->mTransform.GetPropertyMap( transform );
254   map.Insert( DevelVisual::Property::TRANSFORM, transform );
255
256   bool premultipliedAlpha( IsPreMultipliedAlphaEnabled() );
257   map.Insert( DevelVisual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha );
258
259   // Note, Color and Primitive will also insert their own mix color into the map
260   // which is ok, because they have a different key value range.
261   map.Insert( DevelVisual::Property::MIX_COLOR, GetMixColor() );
262 }
263
264 void Visual::Base::EnablePreMultipliedAlpha( bool preMultipled )
265 {
266   if( preMultipled )
267   {
268     mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
269   }
270   else
271   {
272     mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
273   }
274
275   if( mImpl->mRenderer )
276   {
277     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultipled);
278   }
279 }
280
281 bool Visual::Base::IsPreMultipliedAlphaEnabled() const
282 {
283   return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
284 }
285
286 void Visual::Base::DoSetOffStage( Actor& actor )
287 {
288   actor.RemoveRenderer( mImpl->mRenderer );
289   mImpl->mRenderer.Reset();
290 }
291
292 bool Visual::Base::IsOnStage() const
293 {
294   return mImpl->mFlags & Impl::IS_ON_STAGE;
295 }
296
297 bool Visual::Base::IsFromCache() const
298 {
299   return mImpl->mFlags & Impl::IS_FROM_CACHE;
300 }
301
302 void Visual::Base::RegisterMixColor()
303 {
304   // Only register if not already registered.
305   // (Color and Primitive visuals will register their own and save to this index)
306   if( mImpl->mMixColorIndex == Property::INVALID_INDEX )
307   {
308     mImpl->mMixColorIndex = DevelHandle::RegisterProperty(
309       mImpl->mRenderer,
310       Toolkit::DevelVisual::Property::MIX_COLOR,
311       MIX_COLOR,
312       mImpl->mMixColor );
313
314     if( mImpl->mMixColor.a < 1.f )
315     {
316       mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
317     }
318
319     float preMultipliedAlpha = 0.0f;
320     if( IsPreMultipliedAlphaEnabled() )
321     {
322       preMultipliedAlpha = 1.0f;
323     }
324     mImpl->mRenderer.RegisterProperty( "preMultipliedAlpha", preMultipliedAlpha );
325   }
326 }
327
328 void Visual::Base::SetMixColor( const Vector4& color )
329 {
330   mImpl->mMixColor = color;
331
332   if( mImpl->mRenderer )
333   {
334     mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, color );
335     if( color.a < 1.f )
336     {
337       mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
338     }
339   }
340 }
341
342 const Vector4& Visual::Base::GetMixColor() const
343 {
344   return mImpl->mMixColor;
345 }
346
347 Renderer Visual::Base::GetRenderer()
348 {
349   return mImpl->mRenderer;
350 }
351
352 void Visual::Base::AnimateProperty( Dali::Animation& transition, Internal::TransitionData::Animator& animator )
353 {
354 #if defined(DEBUG_ENABLED)
355   {
356     std::ostringstream oss;
357     oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
358     DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, oss.str().c_str() );
359   }
360 #endif
361
362   Property::Index index = Property::INVALID_INDEX;
363
364   // Get the property index
365   bool isMixColor = false;
366   if( animator.propertyKey == Toolkit::DevelVisual::Property::MIX_COLOR ||
367       animator.propertyKey == MIX_COLOR )
368   {
369     isMixColor = true;
370     index = mImpl->mMixColorIndex;
371   }
372   else if( mImpl->mRenderer )
373   {
374     index = DevelHandle::GetPropertyIndex( mImpl->mRenderer, animator.propertyKey );
375   }
376
377   Vector4 currentMixColor( mImpl->mMixColor );
378
379   // Set target value into data store
380   if( animator.targetValue.GetType() != Property::NONE )
381   {
382     if( isMixColor )
383     {
384       animator.targetValue.Get( mImpl->mMixColor );
385     }
386     else
387     {
388       // Note: there may be several of these calls if more than one transform property is animated.
389       Property::Map map;
390       if( animator.propertyKey.type == Property::Key::INDEX )
391       {
392         map.Add( animator.propertyKey.indexKey, animator.targetValue );
393       }
394       else
395       {
396         map.Add( animator.propertyKey.stringKey, animator.targetValue );
397       }
398
399       mImpl->mTransform.UpdatePropertyMap( map );
400     }
401   }
402
403   if( index != Property::INVALID_INDEX )
404   {
405     if( mImpl->mRenderer )
406     {
407       if( animator.animate == false )
408       {
409         mImpl->mRenderer.SetProperty( index, animator.targetValue );
410         if( isMixColor )
411         {
412           mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, mImpl->mMixColor.a < 1.0 ? BlendMode::ON : BlendMode::AUTO );
413         }
414       }
415       else
416       {
417         if( animator.initialValue.GetType() != Property::NONE )
418         {
419           if( isMixColor )
420           {
421             animator.initialValue.Get( currentMixColor );
422           }
423
424 #if defined(DEBUG_ENABLED)
425           {
426             std::ostringstream oss;
427             oss << animator.initialValue;
428             DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "  Setting Initial Value - %s\n", oss.str().c_str() );
429           }
430 #endif
431           mImpl->mRenderer.SetProperty( index, animator.initialValue );
432         }
433
434         if( isMixColor )
435         {
436           mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE,
437                                         ( currentMixColor.a < 1.0 || mImpl->mMixColor.a < 1.0 ) ? BlendMode::ON : BlendMode::AUTO );
438         }
439
440         if( ! transition )
441         {
442           transition = Dali::Animation::New( 0.1f );
443         }
444
445 #if defined(DEBUG_ENABLED)
446         {
447           std::ostringstream oss;
448           oss << animator.targetValue;
449           DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "  Animating to Value - %s\n", oss.str().c_str() );
450         }
451 #endif
452
453         transition.AnimateTo( Property( mImpl->mRenderer, index ),
454                               animator.targetValue,
455                               animator.alphaFunction,
456                               TimePeriod( animator.timePeriodDelay,
457                                           animator.timePeriodDuration ) );
458
459         if( isMixColor && currentMixColor.a < 1.0f && mImpl->mMixColor.a >= 1.0f )
460         {
461           // When it becomes opaque, set the blend mode back to automatically
462           if( ! mImpl->mBlendSlotDelegate )
463           {
464             mImpl->mBlendSlotDelegate = new SlotDelegate<Visual::Base>(this);
465           }
466           transition.FinishedSignal().Connect( *(mImpl->mBlendSlotDelegate), &Visual::Base::OnMixColorFinished );
467         }
468       }
469     }
470   }
471 }
472
473 void Visual::Base::OnMixColorFinished( Animation& animation )
474 {
475   if( mImpl->mRenderer )
476   {
477     DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::OnMixColorFinished()\n");
478     mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE,
479                                   ( mImpl->mMixColor.a < 1.0 ) ? BlendMode::ON : BlendMode::AUTO );
480   }
481   delete mImpl->mBlendSlotDelegate;
482   mImpl->mBlendSlotDelegate = NULL;
483 }
484
485 } // namespace Internal
486
487 } // namespace Toolkit
488
489 } // namespace Dali