2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "visual-base-impl.h"
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>
27 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
28 #include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
29 #include <dali-toolkit/public-api/visuals/visual-properties.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
31 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35 #if defined(DEBUG_ENABLED)
36 Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VISUAL_BASE" );
39 const char * const PRE_MULTIPLIED_ALPHA_PROPERTY( "preMultipliedAlpha" );
51 Visual::Base::Base( VisualFactoryCache& factoryCache )
52 : mImpl( new Impl() ),
53 mFactoryCache( factoryCache )
62 void Visual::Base::SetCustomShader( const Property::Map& shaderMap )
64 if( mImpl->mCustomShader )
66 mImpl->mCustomShader->SetPropertyMap( shaderMap );
70 mImpl->mCustomShader = new Impl::CustomShader( shaderMap );
74 void Visual::Base::SetProperties( const Property::Map& propertyMap )
76 for( size_t i = 0; i < propertyMap.Count(); ++i )
78 const KeyValuePair& pair = propertyMap.GetKeyValue( i );
79 const Property::Key& key = pair.first;
80 const Property::Value& value = pair.second;
82 Property::Key matchKey = key;
83 if( matchKey.type == Property::Key::STRING )
85 if( matchKey == CUSTOM_SHADER )
87 matchKey = Property::Key( Toolkit::Visual::Property::SHADER );
89 else if( matchKey == TRANSFORM )
91 matchKey = Property::Key( Toolkit::Visual::Property::TRANSFORM );
93 else if( matchKey == PREMULTIPLIED_ALPHA )
95 matchKey = Property::Key( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA );
97 else if( matchKey == MIX_COLOR )
99 matchKey = Property::Key( Toolkit::Visual::Property::MIX_COLOR );
101 else if( matchKey == OPACITY )
103 matchKey = Property::Key( Toolkit::Visual::Property::OPACITY );
107 switch( matchKey.indexKey )
109 case Toolkit::Visual::Property::SHADER:
111 Property::Map shaderMap;
112 if( value.Get( shaderMap ) )
114 SetCustomShader( shaderMap );
119 case Toolkit::Visual::Property::TRANSFORM:
122 if( value.Get( map ) )
124 mImpl->mTransform.SetPropertyMap( map );
129 case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
131 bool premultipliedAlpha = false;
132 if( value.Get( premultipliedAlpha ) )
134 EnablePreMultipliedAlpha( premultipliedAlpha );
139 case Toolkit::Visual::Property::MIX_COLOR:
142 if( value.Get( mixColor ) )
144 if( value.GetType() == Property::VECTOR4 )
146 SetMixColor( mixColor );
150 Vector3 mixColor3(mixColor);
151 SetMixColor( mixColor3 );
156 case Toolkit::Visual::Property::OPACITY:
159 if( value.Get( opacity ) )
161 mImpl->mMixColor.a = opacity;
162 SetMixColor( mImpl->mMixColor );
169 DoSetProperties( propertyMap );
172 void Visual::Base::SetTransformAndSize( const Property::Map& transform, Size controlSize )
174 mImpl->mControlSize = controlSize;
175 mImpl->mTransform.UpdatePropertyMap( transform );
177 #if defined(DEBUG_ENABLED)
178 std::ostringstream oss;
180 DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::SetTransformAndSize(%s) - [\e[1;32mtransform: %s controlSize: (%3.1f, %3.1f)]\e[0m\n",
181 GetName().c_str(), oss.str().c_str(), controlSize.x, controlSize.y );
187 void Visual::Base::SetName( const std::string& name )
192 const std::string& Visual::Base::GetName()
197 float Visual::Base::GetHeightForWidth( float width )
199 float aspectCorrectedHeight = 0.f;
201 GetNaturalSize( naturalSize );
202 if( naturalSize.width )
204 aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
206 return aspectCorrectedHeight;
209 float Visual::Base::GetWidthForHeight( float height )
211 float aspectCorrectedWidth = 0.f;
213 GetNaturalSize( naturalSize );
214 if( naturalSize.height > 0.0f )
216 aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
218 return aspectCorrectedWidth;
221 void Visual::Base::GetNaturalSize( Vector2& naturalSize )
223 naturalSize = Vector2::ZERO;
226 void Visual::Base::SetDepthIndex( int index )
228 mImpl->mDepthIndex = index;
229 if( mImpl->mRenderer )
231 mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
235 int Visual::Base::GetDepthIndex() const
237 return mImpl->mDepthIndex;
240 void Visual::Base::SetOnStage( Actor& actor )
244 // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
245 // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
246 DoSetOnStage( actor );
248 if( mImpl->mRenderer )
252 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
253 mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
254 mImpl->mFlags |= Impl::IS_ON_STAGE; // Only sets the flag if renderer exists
259 void Visual::Base::SetOffStage( Actor& actor )
263 DoSetOffStage( actor );
264 mImpl->mMixColorIndex = Property::INVALID_INDEX;
265 mImpl->mOpacityIndex = Property::INVALID_INDEX;
266 mImpl->mFlags &= ~Impl::IS_ON_STAGE;
270 void Visual::Base::CreatePropertyMap( Property::Map& map ) const
272 DoCreatePropertyMap( map );
274 if( mImpl->mCustomShader )
276 mImpl->mCustomShader->CreatePropertyMap( map );
279 Property::Map transform;
280 mImpl->mTransform.GetPropertyMap( transform );
281 map.Insert( Toolkit::Visual::Property::TRANSFORM, transform );
283 bool premultipliedAlpha( IsPreMultipliedAlphaEnabled() );
284 map.Insert( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha );
286 // Note, Color and Primitive will also insert their own mix color into the map
287 // which is ok, because they have a different key value range.
288 map.Insert( Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor ); // vec4
289 map.Insert( Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a );
292 void Visual::Base::CreateInstancePropertyMap( Property::Map& map ) const
294 DoCreateInstancePropertyMap( map );
296 if( mImpl->mCustomShader )
298 mImpl->mCustomShader->CreatePropertyMap( map );
301 //map.Insert( Toolkit::Visual::Property::DEPTH_INDEX, mImpl->mDepthIndex );
302 //map.Insert( Toolkit::Visual::Property::ENABLED, (bool) mImpl->mRenderer );
306 void Visual::Base::EnablePreMultipliedAlpha( bool preMultiplied )
310 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
314 mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
317 if( mImpl->mRenderer )
319 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied);
320 mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, static_cast<float>( preMultiplied ) );
324 bool Visual::Base::IsPreMultipliedAlphaEnabled() const
326 return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
329 void Visual::Base::DoSetOffStage( Actor& actor )
331 actor.RemoveRenderer( mImpl->mRenderer );
332 mImpl->mRenderer.Reset();
335 bool Visual::Base::IsOnStage() const
337 return mImpl->mFlags & Impl::IS_ON_STAGE;
340 void Visual::Base::RegisterMixColor()
342 // Only register if not already registered.
343 // (Color and Primitive visuals will register their own and save to this index)
344 if( mImpl->mMixColorIndex == Property::INVALID_INDEX )
346 mImpl->mMixColorIndex = DevelHandle::RegisterProperty(
348 Toolkit::Visual::Property::MIX_COLOR,
350 Vector3(mImpl->mMixColor) );
353 if( mImpl->mMixColor.a < 1.f )
355 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
358 if( mImpl->mOpacityIndex == Property::INVALID_INDEX )
360 mImpl->mOpacityIndex = DevelHandle::RegisterProperty(
362 Toolkit::Visual::Property::OPACITY,
364 mImpl->mMixColor.a );
367 float preMultipliedAlpha = 0.0f;
368 if( IsPreMultipliedAlphaEnabled() )
370 preMultipliedAlpha = 1.0f;
372 mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, preMultipliedAlpha );
375 void Visual::Base::SetMixColor( const Vector4& color )
377 mImpl->mMixColor = color;
379 if( mImpl->mRenderer )
381 mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, Vector3(color) );
382 mImpl->mRenderer.SetProperty( mImpl->mOpacityIndex, color.a );
385 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
390 void Visual::Base::SetMixColor( const Vector3& color )
392 mImpl->mMixColor.r = color.r;
393 mImpl->mMixColor.g = color.g;
394 mImpl->mMixColor.b = color.b;
396 if( mImpl->mRenderer )
398 mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, color );
402 const Vector4& Visual::Base::GetMixColor() const
404 return mImpl->mMixColor;
407 void Visual::Base::AddResourceObserver( Visual::ResourceObserver& observer)
409 mImpl->mResourceObserver = &observer;
412 void Visual::Base::RemoveResourceObserver( Visual::ResourceObserver& observer )
414 mImpl->mResourceObserver = NULL;
417 void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus)
419 if( mImpl->mResourceStatus != resourceStatus )
421 mImpl->mResourceStatus = resourceStatus;
423 if( mImpl->mResourceObserver )
425 // observer is currently a control impl
426 mImpl->mResourceObserver->ResourceReady( *this );
431 bool Visual::Base::IsResourceReady() const
433 return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY );
436 Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const
438 return mImpl->mResourceStatus;
441 Renderer Visual::Base::GetRenderer()
443 return mImpl->mRenderer;
446 Property::Index Visual::Base::GetPropertyIndex( Property::Key key )
448 Property::Index index = DevelHandle::GetPropertyIndex( mImpl->mRenderer, key );
450 if( index == Property::INVALID_INDEX )
452 // Is it a shader property?
453 Shader shader = mImpl->mRenderer.GetShader();
454 index = DevelHandle::GetPropertyIndex( shader, key );
455 if( index != Property::INVALID_INDEX )
457 // Yes - we should register it in the Renderer so it can be set / animated
458 // independently, as shaders are shared across multiple renderers.
460 Property::Index keyIndex( Property::INVALID_KEY );
461 if( key.type == Property::Key::INDEX )
463 keyName = shader.GetPropertyName( index );
464 keyIndex = key.indexKey;
468 keyName = key.stringKey;
469 // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
471 Property::Value value = shader.GetProperty( index );
472 index = DevelHandle::RegisterProperty( mImpl->mRenderer, keyIndex, keyName, value );
478 void Visual::Base::SetupTransition(
479 Dali::Animation& transition,
480 Internal::TransitionData::Animator& animator,
481 Property::Index index,
482 Property::Value& initialValue,
483 Property::Value& targetValue )
485 if( index != Property::INVALID_INDEX )
487 if( mImpl->mRenderer )
489 if( animator.animate == false )
491 mImpl->mRenderer.SetProperty( index, targetValue );
495 if( animator.initialValue.GetType() != Property::NONE )
497 mImpl->mRenderer.SetProperty( index, initialValue );
502 transition = Dali::Animation::New( 0.1f );
505 transition.AnimateTo( Property( mImpl->mRenderer, index ),
507 animator.alphaFunction,
508 TimePeriod( animator.timePeriodDelay,
509 animator.timePeriodDuration ) );
515 void Visual::Base::AnimateProperty(
516 Dali::Animation& transition,
517 Internal::TransitionData::Animator& animator )
519 #if defined(DEBUG_ENABLED)
521 std::ostringstream oss;
522 oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
523 DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, oss.str().c_str() );
528 DoCreatePropertyMap( map );
529 Property::Value* valuePtr = map.Find( Toolkit::Visual::Property::TYPE );
533 valuePtr->Get( visualType );
536 if( animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
537 animator.propertyKey == MIX_COLOR ||
538 ( visualType == Toolkit::Visual::COLOR &&
539 animator.propertyKey == ColorVisual::Property::MIX_COLOR ) ||
540 ( visualType == Toolkit::Visual::PRIMITIVE &&
541 animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR ) )
543 AnimateMixColorProperty( transition, animator );
545 else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
546 animator.propertyKey == OPACITY )
548 AnimateOpacityProperty( transition, animator );
550 else if( mImpl->mRenderer )
552 AnimateRendererProperty( transition, animator );
556 void Visual::Base::AnimateOpacityProperty(
557 Dali::Animation& transition,
558 Internal::TransitionData::Animator& animator )
560 Property::Index index = mImpl->mOpacityIndex;
562 bool isOpaque = mImpl->mMixColor.a >= 1.0f;
564 if( index != Property::INVALID_INDEX )
566 float initialOpacity;
567 if( animator.initialValue.Get( initialOpacity ) )
569 isOpaque = (initialOpacity >= 1.0f);
573 if( animator.targetValue.Get( targetOpacity ) )
575 mImpl->mMixColor.a = targetOpacity;
578 SetupTransition( transition, animator, index, animator.initialValue, animator.targetValue );
579 SetupBlendMode( transition, isOpaque, animator.animate );
583 void Visual::Base::AnimateRendererProperty(
584 Dali::Animation& transition,
585 Internal::TransitionData::Animator& animator )
587 Property::Index index = GetPropertyIndex( animator.propertyKey );
588 if( index != Property::INVALID_INDEX )
590 if( animator.targetValue.GetType() != Property::NONE )
592 // Try writing target value into transform property map
593 // if it's not a valid key, then it won't alter mTransform
595 if( animator.propertyKey.type == Property::Key::INDEX )
597 map.Add( animator.propertyKey.indexKey, animator.targetValue );
601 map.Add( animator.propertyKey.stringKey, animator.targetValue );
604 mImpl->mTransform.UpdatePropertyMap( map );
607 SetupTransition( transition, animator, index, animator.initialValue, animator.targetValue );
611 void Visual::Base::AnimateMixColorProperty(
612 Dali::Animation& transition,
613 Internal::TransitionData::Animator& animator )
615 Property::Index index = mImpl->mMixColorIndex;
616 bool animateOpacity = false;
617 bool isOpaque = true;
619 Property::Value initialOpacity;
620 Property::Value targetOpacity;
621 Property::Value initialMixColor;
622 Property::Value targetMixColor;
624 if( index != Property::INVALID_INDEX )
626 Vector4 initialColor;
627 if( animator.initialValue.Get(initialColor) )
629 if( animator.initialValue.GetType() == Property::VECTOR4 )
631 // if there is an initial color specifying alpha, test it
632 isOpaque = initialColor.a >= 1.0f;
633 initialOpacity = initialColor.a;
635 initialMixColor = Vector3( initialColor );
638 // Set target value into data store
639 if( animator.targetValue.GetType() != Property::NONE )
642 animator.targetValue.Get(mixColor);
643 if( animator.targetValue.GetType() == Property::VECTOR4 )
645 mImpl->mMixColor.a = mixColor.a;
646 targetOpacity = mixColor.a;
647 animateOpacity = true;
650 mImpl->mMixColor.r = mixColor.r;
651 mImpl->mMixColor.g = mixColor.g;
652 mImpl->mMixColor.b = mixColor.b;
653 targetMixColor = Vector3(mixColor);
656 SetupTransition( transition, animator, index, initialMixColor, targetMixColor );
659 SetupTransition( transition, animator, mImpl->mOpacityIndex, initialOpacity, targetOpacity );
660 SetupBlendMode( transition, isOpaque, animator.animate );
665 void Visual::Base::SetupBlendMode( Animation& transition, bool isInitialOpaque, bool animating )
667 // Ensure the blend mode is turned on if we are animating opacity, and
668 // turned off after the animation ends if the final value is opaque
669 if( ! isInitialOpaque || mImpl->mMixColor.a < 1.0f )
671 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
673 if( animating == true && mImpl->mMixColor.a >= 1.0f )
675 // When it becomes opaque, set the blend mode back to automatically
676 if( ! mImpl->mBlendSlotDelegate )
678 mImpl->mBlendSlotDelegate = new SlotDelegate<Visual::Base>(this);
680 transition.FinishedSignal().Connect( *(mImpl->mBlendSlotDelegate),
681 &Visual::Base::OnMixColorFinished );
686 void Visual::Base::OnMixColorFinished( Animation& animation )
688 if( mImpl->mRenderer )
690 DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::OnMixColorFinished()\n");
691 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE,
692 ( mImpl->mMixColor.a < 1.0 ) ? BlendMode::ON : BlendMode::AUTO );
694 delete mImpl->mBlendSlotDelegate;
695 mImpl->mBlendSlotDelegate = NULL;
698 } // namespace Internal
700 } // namespace Toolkit