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/internal/event/images/nine-patch-image-impl.h>
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/internal/event/common/property-index-ranges.h>
24 #include <dali/internal/event/images/image-connector.h>
25 #include <dali/public-api/scripting/scripting.h>
30 const Property::Index ImageActor::PIXEL_AREA = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
31 const Property::Index ImageActor::FADE_IN = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 1;
32 const Property::Index ImageActor::FADE_IN_DURATION = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 2;
33 const Property::Index ImageActor::STYLE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 3;
34 const Property::Index ImageActor::BORDER = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 4;
35 const Property::Index ImageActor::IMAGE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 5;
39 bool ImageActor::mFirstInstance = true;
40 Actor::DefaultPropertyLookup* ImageActor::mDefaultImageActorPropertyLookup = NULL;
47 return Dali::ImageActor::New();
50 TypeRegistration mType( typeid(Dali::ImageActor), typeid(Dali::RenderableActor), Create );
52 const std::string DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[] =
61 const int DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT = sizeof( DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES ) / sizeof( std::string );
63 const Property::Type DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT] =
65 Property::RECTANGLE, // "pixel-area",
66 Property::BOOLEAN, // "fade-in",
67 Property::FLOAT, // "fade-in-duration",
68 Property::STRING, // "style",
69 Property::VECTOR4, // "border",
70 Property::MAP, // "image",
73 ImageActor::Style StyleEnum(const std::string &s)
75 if(s == "STYLE_NINE_PATCH")
77 return Dali::ImageActor::STYLE_NINE_PATCH;
79 else // if(s == "QUAD")
81 return Dali::ImageActor::STYLE_QUAD;
85 std::string StyleString(const ImageActor::Style style)
87 if(style == Dali::ImageActor::STYLE_NINE_PATCH)
89 return "STYLE_NINE_PATCH";
91 else // if(s == "QUAD")
98 ImageActorPtr ImageActor::New( Image* anImage )
100 ImageActorPtr actor( new ImageActor() );
101 ImagePtr theImage( anImage );
103 // Second-phase construction
105 NinePatchImage* ninePatchImage = NULL;
107 // Automatically convert upcasted nine-patch images to cropped bitmap
108 ninePatchImage = NinePatchImage::GetNinePatchImage( anImage );
110 if( ninePatchImage != NULL )
112 theImage = ninePatchImage->CreateCroppedBitmapImage();
115 // Create the attachment
116 actor->mImageAttachment = ImageAttachment::New( *actor->mNode, theImage.Get() );
117 actor->Attach( *actor->mImageAttachment );
119 // Adjust the actor's size
122 actor->mImageNext.Set( theImage.Get(), false );
123 actor->OnImageSet( *theImage );
124 actor->SetNaturalSize( *theImage );
127 if( ninePatchImage != NULL )
129 actor->SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
130 Vector4 border = ninePatchImage->GetStretchBorders();
131 actor->SetNinePatchBorder( border, true );
138 ImageActorPtr ImageActor::New( Image* image, const PixelArea& pixelArea )
141 ImageActorPtr actor = New( image );
142 // then set the pixel area
143 actor->mImageAttachment->SetPixelArea( pixelArea );
147 void ImageActor::OnInitialize()
149 if(ImageActor::mFirstInstance)
151 mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
152 const int start = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
153 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
155 (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
157 ImageActor::mFirstInstance = false;
161 void ImageActor::SetImage( Image* image )
163 Image* currentImage = static_cast<Image*>(mImageAttachment->GetImage().GetObjectPtr());
164 // early exit if it's the same image
165 if ( currentImage == image || mImageNext.Get() == image )
170 mLoadedConnection.DisconnectAll();
172 ImagePtr imagePtr( image );
174 // Automatically convert nine-patch images to cropped bitmap
175 NinePatchImage* ninePatchImage = NinePatchImage::GetNinePatchImage( image );
178 imagePtr = ninePatchImage->CreateCroppedBitmapImage();
181 mImageNext.Set( imagePtr.Get(), OnStage() );
185 SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
186 SetNinePatchBorder( ninePatchImage->GetStretchBorders(), true );
191 mImageAttachment->SetImage( NULL );
195 // don't disconnect currently shown image until we made sure that the new one is loaded
196 OnImageSet( *imagePtr.Get() );
200 Dali::Image ImageActor::GetImage()
202 return mImageAttachment->GetImage();
205 void ImageActor::SetToNaturalSize()
207 mUsingNaturalSize = true;
208 Dali::Image image = mImageAttachment->GetImage();
212 SetNaturalSize( GetImplementation(image) );
216 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
218 mImageAttachment->SetPixelArea( pixelArea );
220 if( mUsingNaturalSize )
222 mInternalSetSize = true;
223 SetSize(pixelArea.width, pixelArea.height);
224 mInternalSetSize = false;
228 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
230 return mImageAttachment->GetPixelArea();
233 bool ImageActor::IsPixelAreaSet() const
235 return mImageAttachment->IsPixelAreaSet();
238 void ImageActor::ClearPixelArea()
240 mImageAttachment->ClearPixelArea();
242 if( mUsingNaturalSize )
244 Dali::Image image = mImageAttachment->GetImage();
247 mInternalSetSize = true;
248 SetSize(GetImplementation(image).GetNaturalSize());
249 mInternalSetSize = false;
254 void ImageActor::SetStyle( Style style )
256 mImageAttachment->SetStyle( style );
259 ImageActor::Style ImageActor::GetStyle() const
261 return mImageAttachment->GetStyle();
264 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
266 mImageAttachment->SetNinePatchBorder( border, inPixels );
269 Vector4 ImageActor::GetNinePatchBorder() const
271 return mImageAttachment->GetNinePatchBorder();
274 void ImageActor::SetFadeIn( bool enableFade )
276 mFadeIn = enableFade;
279 bool ImageActor::GetFadeIn() const
284 void ImageActor::SetFadeInDuration( float durationSeconds )
286 mFadeInDuration = durationSeconds;
289 float ImageActor::GetFadeInDuration() const
291 return mFadeInDuration;
294 ImageAttachment& ImageActor::GetImageAttachment()
296 return *mImageAttachment;
299 Vector2 ImageActor::GetCurrentImageSize() const
304 // get the texture size / pixel area if only a subset of it is displayed
305 if( IsPixelAreaSet() )
307 PixelArea area(GetPixelArea());
308 return Vector2(area.width, area.height );
312 return Vector2( GetCurrentSize() );
316 RenderableAttachment& ImageActor::GetRenderableAttachment() const
318 DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
319 return *mImageAttachment;
322 ImageActor::ImageActor()
324 mUsingNaturalSize(true),
325 mInternalSetSize(false),
327 mFadeInitial( true ),
328 mLoadedConnection( this ),
329 mFadeInDuration( 1.0f )
333 ImageActor::~ImageActor()
335 // ScopedConnection disconnects automatically
338 void ImageActor::OnImageSet( Image& image )
340 // observe image loaded
341 if( Dali::ResourceLoading == image.GetLoadingState() && ! image.GetFilename().empty() )
343 image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
347 // image already loaded, or generated
348 ImageLoaded( Dali::Image(&image) );
352 void ImageActor::SetNaturalSize( Image& image )
354 if( mUsingNaturalSize )
357 if( IsPixelAreaSet() )
359 PixelArea area(GetPixelArea());
360 size.width = area.width;
361 size.height = area.height;
365 size = image.GetNaturalSize();
368 mInternalSetSize = true;
370 mInternalSetSize = false;
374 void ImageActor::OnSizeSet( const Vector3& targetSize )
376 if( !mInternalSetSize )
378 mUsingNaturalSize = false;
382 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
384 mUsingNaturalSize = false;
387 void ImageActor::OnStageConnectionInternal()
391 mImageNext.OnStageConnect();
394 void ImageActor::OnStageDisconnectionInternal()
396 mImageNext.OnStageDisconnect();
399 void ImageActor::ImageLoaded( Dali::Image image )
401 DALI_ASSERT_DEBUG (image && "Image handle empty!");
403 // TODO: Handle case where image loading failed
405 // Need to keep mUploadedConnection connected as image may change later through Reload
406 // Note: Reloaded images may have changed size.
408 // Set the attachment's image once we know the image has loaded to prevent
409 // blank frames during load / reload.
410 mImageAttachment->SetImage( &GetImplementation( image ) );
412 // If size has never been set by application
413 if( mUsingNaturalSize )
415 // If a pixel area has been set, use this size
416 if( IsPixelAreaSet() )
418 const PixelArea& area = GetPixelArea();
419 mInternalSetSize = true;
420 SetSize(area.width, area.height);
421 mInternalSetSize = false;
425 mInternalSetSize = true;
426 SetSize( GetImplementation(image).GetNaturalSize() );
427 mInternalSetSize = false;
431 // fade in if required
435 void ImageActor::FadeIn()
437 // only fade in if enabled and newly displayed on screen
438 if( mFadeIn && mFadeInitial && ( mFadeInDuration > 0.0f ) )
440 // need to set opacity immediately to 0 otherwise child actors might get rendered
443 Dali::Image image = mImageAttachment->GetImage();
445 // Fade-in when on-stage & the image is loaded
448 image.GetLoadingState() == Dali::ResourceLoadingSucceeded)
450 // fire and forget animation; will clean up after it's finished
451 Dali::Animation animation = Dali::Animation::New( mFadeInDuration );
452 animation.OpacityTo( Dali::Actor( this ), 1.0f, AlphaFunctions::EaseOut );
454 mFadeInitial = false;
459 unsigned int ImageActor::GetDefaultPropertyCount() const
461 return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
464 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
466 RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
468 indices.reserve( indices.size() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT );
470 int index = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
471 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i, ++index )
473 indices.push_back( index );
477 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
479 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
481 return RenderableActor::IsDefaultPropertyWritable(index);
489 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
491 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
493 return RenderableActor::IsDefaultPropertyAnimatable(index);
501 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
503 if( index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT )
505 return RenderableActor::IsDefaultPropertyAConstraintInput(index);
507 return true; // Our properties can be used as input to constraints.
510 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
512 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
514 return RenderableActor::GetDefaultPropertyType(index);
518 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
520 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
522 return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index];
526 // index out-of-bounds
527 return Property::NONE;
532 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
534 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
536 return RenderableActor::GetDefaultPropertyName(index);
540 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
542 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
544 return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index];
548 // index out-of-bounds
549 static const std::string INVALID_PROPERTY_NAME;
550 return INVALID_PROPERTY_NAME;
555 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
557 Property::Index index = Property::INVALID_INDEX;
559 DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
561 // Look for name in current class' default properties
562 DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
563 if ( mDefaultImageActorPropertyLookup->end() != result )
565 index = result->second;
569 // If not found, check in base class
570 index = RenderableActor::GetDefaultPropertyIndex( name );
576 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
578 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
580 RenderableActor::SetDefaultProperty(index, propertyValue);
586 case Dali::ImageActor::PIXEL_AREA:
588 SetPixelArea(propertyValue.Get<Rect<int> >());
591 case Dali::ImageActor::FADE_IN:
593 SetFadeIn(propertyValue.Get<bool>());
596 case Dali::ImageActor::FADE_IN_DURATION:
598 SetFadeInDuration(propertyValue.Get<float>());
601 case Dali::ImageActor::STYLE:
603 SetStyle(StyleEnum(propertyValue.Get<std::string>()));
606 case Dali::ImageActor::BORDER:
608 SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
611 case Dali::ImageActor::IMAGE:
613 Dali::Image img = Scripting::NewImage( propertyValue );
616 SetImage( &GetImplementation(img) );
620 DALI_LOG_WARNING("Cannot create image from property value\n");
626 DALI_LOG_WARNING("Unknown property (%d)\n", index);
634 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
637 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
639 ret = RenderableActor::GetDefaultProperty(index);
645 case Dali::ImageActor::PIXEL_AREA:
647 Rect<int> r = GetPixelArea();
651 case Dali::ImageActor::FADE_IN:
656 case Dali::ImageActor::FADE_IN_DURATION:
658 ret = GetFadeInDuration();
661 case Dali::ImageActor::STYLE:
663 ret = StyleString(GetStyle());
666 case Dali::ImageActor::BORDER:
668 ret = GetNinePatchBorder();
671 case Dali::ImageActor::IMAGE:
674 Scripting::CreatePropertyMap( mImageAttachment->GetImage(), map );
675 ret = Property::Value( map );
680 DALI_LOG_WARNING("Unknown property (%d)\n", index);
690 } // namespace Internal