2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/event/actors/image-actor-impl.h>
21 #include <dali/public-api/object/type-registry.h>
22 #include <dali/internal/event/common/property-index-ranges.h>
23 #include <dali/internal/event/images/image-connector.h>
24 #include <dali/public-api/scripting/scripting.h>
29 const Property::Index ImageActor::PIXEL_AREA = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
30 const Property::Index ImageActor::FADE_IN = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 1;
31 const Property::Index ImageActor::FADE_IN_DURATION = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 2;
32 const Property::Index ImageActor::STYLE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 3;
33 const Property::Index ImageActor::BORDER = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 4;
34 const Property::Index ImageActor::IMAGE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 5;
38 bool ImageActor::mFirstInstance = true;
39 Actor::DefaultPropertyLookup* ImageActor::mDefaultImageActorPropertyLookup = NULL;
46 return Dali::ImageActor::New();
49 TypeRegistration mType( typeid(Dali::ImageActor), typeid(Dali::RenderableActor), Create );
51 const std::string DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[] =
60 const int DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT = sizeof( DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES ) / sizeof( std::string );
62 const Property::Type DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT] =
64 Property::RECTANGLE, // "pixel-area",
65 Property::BOOLEAN, // "fade-in",
66 Property::FLOAT, // "fade-in-duration",
67 Property::STRING, // "style",
68 Property::VECTOR4, // "border",
69 Property::MAP, // "image",
72 ImageActor::Style StyleEnum(const std::string &s)
74 if(s == "STYLE_NINE_PATCH")
76 return Dali::ImageActor::STYLE_NINE_PATCH;
78 else // if(s == "QUAD")
80 return Dali::ImageActor::STYLE_QUAD;
84 std::string StyleString(const ImageActor::Style style)
86 if(style == Dali::ImageActor::STYLE_NINE_PATCH)
88 return "STYLE_NINE_PATCH";
90 else // if(s == "QUAD")
97 ImageActorPtr ImageActor::New( Image* image )
99 ImageActorPtr actor( new ImageActor() );
101 // Second-phase construction
104 // Create the attachment
105 actor->mImageAttachment = ImageAttachment::New( *actor->mNode, image );
106 actor->Attach( *actor->mImageAttachment );
108 // Adjust the actor's size
111 actor->mImageNext.Set( image, false );
112 actor->OnImageSet( *image );
113 actor->SetNaturalSize( *image );
119 ImageActorPtr ImageActor::New( Image* image, const PixelArea& pixelArea )
122 ImageActorPtr actor = New( image );
123 // then set the pixel area
124 actor->mImageAttachment->SetPixelArea( pixelArea );
128 void ImageActor::OnInitialize()
130 if(ImageActor::mFirstInstance)
132 mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
133 const int start = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
134 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
136 (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
138 ImageActor::mFirstInstance = false;
142 void ImageActor::SetImage( Image* image )
144 Image* currentImage = static_cast<Image*>(mImageAttachment->GetImage().GetObjectPtr());
145 // early exit if it's the same image
146 if ( currentImage == image || mImageNext.Get() == image )
151 mLoadedConnection.DisconnectAll();
153 mImageNext.Set( image, OnStage() );
157 mImageAttachment->SetImage( NULL );
161 // don't disconnect currently shown image until we made sure that the new one is loaded
162 OnImageSet( *image );
166 Dali::Image ImageActor::GetImage()
168 return mImageAttachment->GetImage();
171 void ImageActor::SetToNaturalSize()
173 mUsingNaturalSize = true;
174 Dali::Image image = mImageAttachment->GetImage();
178 SetNaturalSize( GetImplementation(image) );
182 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
184 mImageAttachment->SetPixelArea( pixelArea );
186 if( mUsingNaturalSize )
188 mInternalSetSize = true;
189 SetSize(pixelArea.width, pixelArea.height);
190 mInternalSetSize = false;
194 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
196 return mImageAttachment->GetPixelArea();
199 bool ImageActor::IsPixelAreaSet() const
201 return mImageAttachment->IsPixelAreaSet();
204 void ImageActor::ClearPixelArea()
206 mImageAttachment->ClearPixelArea();
208 if( mUsingNaturalSize )
210 Dali::Image image = mImageAttachment->GetImage();
213 mInternalSetSize = true;
214 SetSize(GetImplementation(image).GetNaturalSize());
215 mInternalSetSize = false;
220 void ImageActor::SetStyle( Style style )
222 mImageAttachment->SetStyle( style );
225 ImageActor::Style ImageActor::GetStyle() const
227 return mImageAttachment->GetStyle();
230 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
232 mImageAttachment->SetNinePatchBorder( border, inPixels );
235 Vector4 ImageActor::GetNinePatchBorder() const
237 return mImageAttachment->GetNinePatchBorder();
240 void ImageActor::SetFadeIn( bool enableFade )
242 mFadeIn = enableFade;
245 bool ImageActor::GetFadeIn() const
250 void ImageActor::SetFadeInDuration( float durationSeconds )
252 mFadeInDuration = durationSeconds;
255 float ImageActor::GetFadeInDuration() const
257 return mFadeInDuration;
260 ImageAttachment& ImageActor::GetImageAttachment()
262 return *mImageAttachment;
265 Vector2 ImageActor::GetCurrentImageSize() const
270 // get the texture size / pixel area if only a subset of it is displayed
271 if( IsPixelAreaSet() )
273 PixelArea area(GetPixelArea());
274 return Vector2(area.width, area.height );
278 return Vector2( GetCurrentSize() );
282 RenderableAttachment& ImageActor::GetRenderableAttachment() const
284 DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
285 return *mImageAttachment;
288 ImageActor::ImageActor()
290 mUsingNaturalSize(true),
291 mInternalSetSize(false),
293 mFadeInitial( true ),
294 mLoadedConnection( this ),
295 mFadeInDuration( 1.0f )
299 ImageActor::~ImageActor()
301 // ScopedConnection disconnects automatically
304 void ImageActor::OnImageSet( Image& image )
306 // observe image loaded
307 if( Dali::ResourceLoading == image.GetLoadingState() && ! image.GetFilename().empty() )
309 image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
313 // image already loaded, or generated
314 ImageLoaded( Dali::Image(&image) );
318 void ImageActor::SetNaturalSize( Image& image )
320 if( mUsingNaturalSize )
323 if( IsPixelAreaSet() )
325 PixelArea area(GetPixelArea());
326 size.width = area.width;
327 size.height = area.height;
331 size = image.GetNaturalSize();
334 mInternalSetSize = true;
336 mInternalSetSize = false;
340 void ImageActor::OnSizeSet( const Vector3& targetSize )
342 if( !mInternalSetSize )
344 mUsingNaturalSize = false;
348 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
350 mUsingNaturalSize = false;
353 void ImageActor::OnStageConnectionInternal()
357 mImageNext.OnStageConnect();
360 void ImageActor::OnStageDisconnectionInternal()
362 mImageNext.OnStageDisconnect();
365 void ImageActor::ImageLoaded( Dali::Image image )
367 DALI_ASSERT_DEBUG (image && "Image handle empty!");
369 // TODO: Handle case where image loading failed
371 // Need to keep mUploadedConnection connected as image may change later through Reload
372 // Note: Reloaded images may have changed size.
374 // Set the attachment's image once we know the image has loaded to prevent
375 // blank frames during load / reload.
376 mImageAttachment->SetImage( &GetImplementation( image ) );
378 // If size has never been set by application
379 if( mUsingNaturalSize )
381 // If a pixel area has been set, use this size
382 if( IsPixelAreaSet() )
384 const PixelArea& area = GetPixelArea();
385 mInternalSetSize = true;
386 SetSize(area.width, area.height);
387 mInternalSetSize = false;
391 mInternalSetSize = true;
392 SetSize( GetImplementation(image).GetNaturalSize() );
393 mInternalSetSize = false;
397 // fade in if required
401 void ImageActor::FadeIn()
403 // only fade in if enabled and newly displayed on screen
404 if( mFadeIn && mFadeInitial && ( mFadeInDuration > 0.0f ) )
406 // need to set opacity immediately to 0 otherwise child actors might get rendered
409 Dali::Image image = mImageAttachment->GetImage();
411 // Fade-in when on-stage & the image is loaded
414 image.GetLoadingState() == Dali::ResourceLoadingSucceeded)
416 // fire and forget animation; will clean up after it's finished
417 Dali::Animation animation = Dali::Animation::New( mFadeInDuration );
418 animation.OpacityTo( Dali::Actor( this ), 1.0f, AlphaFunctions::EaseOut );
420 mFadeInitial = false;
425 unsigned int ImageActor::GetDefaultPropertyCount() const
427 return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
430 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
432 RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
434 indices.reserve( indices.size() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT );
436 int index = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
437 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i, ++index )
439 indices.push_back( index );
443 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
445 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
447 return RenderableActor::IsDefaultPropertyWritable(index);
455 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
457 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
459 return RenderableActor::IsDefaultPropertyAnimatable(index);
467 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
469 if( index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT )
471 return RenderableActor::IsDefaultPropertyAConstraintInput(index);
473 return true; // Our properties can be used as input to constraints.
476 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
478 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
480 return RenderableActor::GetDefaultPropertyType(index);
484 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
486 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
488 return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index];
492 // index out-of-bounds
493 return Property::NONE;
498 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
500 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
502 return RenderableActor::GetDefaultPropertyName(index);
506 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
508 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
510 return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index];
514 // index out-of-bounds
515 static const std::string INVALID_PROPERTY_NAME;
516 return INVALID_PROPERTY_NAME;
521 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
523 Property::Index index = Property::INVALID_INDEX;
525 DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
527 // Look for name in current class' default properties
528 DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
529 if ( mDefaultImageActorPropertyLookup->end() != result )
531 index = result->second;
535 // If not found, check in base class
536 index = RenderableActor::GetDefaultPropertyIndex( name );
542 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
544 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
546 RenderableActor::SetDefaultProperty(index, propertyValue);
552 case Dali::ImageActor::PIXEL_AREA:
554 SetPixelArea(propertyValue.Get<Rect<int> >());
557 case Dali::ImageActor::FADE_IN:
559 SetFadeIn(propertyValue.Get<bool>());
562 case Dali::ImageActor::FADE_IN_DURATION:
564 SetFadeInDuration(propertyValue.Get<float>());
567 case Dali::ImageActor::STYLE:
569 SetStyle(StyleEnum(propertyValue.Get<std::string>()));
572 case Dali::ImageActor::BORDER:
574 SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
577 case Dali::ImageActor::IMAGE:
579 Dali::Image img = Scripting::NewImage( propertyValue );
582 SetImage( &GetImplementation(img) );
586 DALI_LOG_WARNING("Cannot create image from property value\n");
592 DALI_LOG_WARNING("Unknown property (%d)\n", index);
600 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
603 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
605 ret = RenderableActor::GetDefaultProperty(index);
611 case Dali::ImageActor::PIXEL_AREA:
613 Rect<int> r = GetPixelArea();
617 case Dali::ImageActor::FADE_IN:
622 case Dali::ImageActor::FADE_IN_DURATION:
624 ret = GetFadeInDuration();
627 case Dali::ImageActor::STYLE:
629 ret = StyleString(GetStyle());
632 case Dali::ImageActor::BORDER:
634 ret = GetNinePatchBorder();
637 case Dali::ImageActor::IMAGE:
640 Scripting::CreatePropertyMap( mImageAttachment->GetImage(), map );
641 ret = Property::Value( map );
646 DALI_LOG_WARNING("Unknown property (%d)\n", index);
656 } // namespace Internal