2 * Copyright (c) 2014 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 <dali/internal/event/actors/image-actor-impl.h>
22 #include <dali/internal/event/images/nine-patch-image-impl.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/internal/event/common/property-index-ranges.h>
25 #include <dali/internal/event/images/image-connector.h>
26 #include <dali/public-api/scripting/scripting.h>
31 const Property::Index ImageActor::PIXEL_AREA = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
32 const Property::Index ImageActor::FADE_IN = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 1;
33 const Property::Index ImageActor::FADE_IN_DURATION = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 2;
34 const Property::Index ImageActor::STYLE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 3;
35 const Property::Index ImageActor::BORDER = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 4;
36 const Property::Index ImageActor::IMAGE = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 5;
40 bool ImageActor::mFirstInstance = true;
41 Actor::DefaultPropertyLookup* ImageActor::mDefaultImageActorPropertyLookup = NULL;
48 return Dali::ImageActor::New();
51 TypeRegistration mType( typeid(Dali::ImageActor), typeid(Dali::RenderableActor), Create );
53 const std::string DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[] =
62 const int DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT = sizeof( DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES ) / sizeof( std::string );
64 const Property::Type DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT] =
66 Property::RECTANGLE, // "pixel-area",
67 Property::BOOLEAN, // "fade-in",
68 Property::FLOAT, // "fade-in-duration",
69 Property::STRING, // "style",
70 Property::VECTOR4, // "border",
71 Property::MAP, // "image",
74 ImageActor::Style StyleEnum(const std::string &s)
76 if(s == "STYLE_NINE_PATCH")
78 return Dali::ImageActor::STYLE_NINE_PATCH;
80 else // if(s == "QUAD")
82 return Dali::ImageActor::STYLE_QUAD;
86 std::string StyleString(const ImageActor::Style style)
88 if(style == Dali::ImageActor::STYLE_NINE_PATCH)
90 return "STYLE_NINE_PATCH";
92 else // if(s == "QUAD")
99 ImageActorPtr ImageActor::New( Image* anImage )
101 ImageActorPtr actor( new ImageActor() );
102 ImagePtr theImage( anImage );
104 // Second-phase construction
106 NinePatchImage* ninePatchImage = NULL;
108 // Automatically convert upcasted nine-patch images to cropped bitmap
109 ninePatchImage = NinePatchImage::GetNinePatchImage( anImage );
111 if( ninePatchImage != NULL )
113 theImage = ninePatchImage->CreateCroppedBitmapImage();
116 // Create the attachment
117 actor->mImageAttachment = ImageAttachment::New( *actor->mNode, theImage.Get() );
118 actor->Attach( *actor->mImageAttachment );
120 // Adjust the actor's size
123 actor->mImageNext.Set( theImage.Get(), false );
124 actor->OnImageSet( *theImage );
125 actor->SetNaturalSize( *theImage );
128 if( ninePatchImage != NULL )
130 actor->SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
131 Vector4 border = ninePatchImage->GetStretchBorders();
132 actor->SetNinePatchBorder( border, true );
139 ImageActorPtr ImageActor::New( Image* image, const PixelArea& pixelArea )
142 ImageActorPtr actor = New( image );
143 // then set the pixel area
144 actor->mImageAttachment->SetPixelArea( pixelArea );
148 void ImageActor::OnInitialize()
150 if(ImageActor::mFirstInstance)
152 mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
153 const int start = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
154 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
156 (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
158 ImageActor::mFirstInstance = false;
162 void ImageActor::SetImage( Image* image )
164 Image* currentImage = static_cast<Image*>(mImageAttachment->GetImage().GetObjectPtr());
165 // early exit if it's the same image
166 if ( currentImage == image || mImageNext.Get() == image )
171 mLoadedConnection.DisconnectAll();
173 ImagePtr imagePtr( image );
175 // Automatically convert nine-patch images to cropped bitmap
176 NinePatchImage* ninePatchImage = NinePatchImage::GetNinePatchImage( image );
179 imagePtr = ninePatchImage->CreateCroppedBitmapImage();
182 mImageNext.Set( imagePtr.Get(), OnStage() );
186 SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
187 SetNinePatchBorder( ninePatchImage->GetStretchBorders(), true );
192 mImageAttachment->SetImage( NULL );
196 // don't disconnect currently shown image until we made sure that the new one is loaded
197 OnImageSet( *imagePtr.Get() );
201 Dali::Image ImageActor::GetImage()
203 return mImageAttachment->GetImage();
206 void ImageActor::SetToNaturalSize()
208 mUsingNaturalSize = true;
209 Dali::Image image = mImageAttachment->GetImage();
213 SetNaturalSize( GetImplementation(image) );
217 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
219 mImageAttachment->SetPixelArea( pixelArea );
221 if( mUsingNaturalSize )
223 mInternalSetSize = true;
224 SetSize(pixelArea.width, pixelArea.height);
225 mInternalSetSize = false;
229 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
231 return mImageAttachment->GetPixelArea();
234 bool ImageActor::IsPixelAreaSet() const
236 return mImageAttachment->IsPixelAreaSet();
239 void ImageActor::ClearPixelArea()
241 mImageAttachment->ClearPixelArea();
243 if( mUsingNaturalSize )
245 Dali::Image image = mImageAttachment->GetImage();
248 mInternalSetSize = true;
249 SetSize(GetImplementation(image).GetNaturalSize());
250 mInternalSetSize = false;
255 void ImageActor::SetStyle( Style style )
257 mImageAttachment->SetStyle( style );
260 ImageActor::Style ImageActor::GetStyle() const
262 return mImageAttachment->GetStyle();
265 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
267 mImageAttachment->SetNinePatchBorder( border, inPixels );
270 Vector4 ImageActor::GetNinePatchBorder() const
272 return mImageAttachment->GetNinePatchBorder();
275 void ImageActor::SetFadeIn( bool enableFade )
277 mFadeIn = enableFade;
280 bool ImageActor::GetFadeIn() const
285 void ImageActor::SetFadeInDuration( float durationSeconds )
287 mFadeInDuration = durationSeconds;
290 float ImageActor::GetFadeInDuration() const
292 return mFadeInDuration;
295 ImageAttachment& ImageActor::GetImageAttachment()
297 return *mImageAttachment;
300 Vector2 ImageActor::GetCurrentImageSize() const
305 // get the texture size / pixel area if only a subset of it is displayed
306 if( IsPixelAreaSet() )
308 PixelArea area(GetPixelArea());
309 return Vector2(area.width, area.height );
313 return Vector2( GetCurrentSize() );
317 RenderableAttachment& ImageActor::GetRenderableAttachment() const
319 DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
320 return *mImageAttachment;
323 ImageActor::ImageActor()
325 mUsingNaturalSize(true),
326 mInternalSetSize(false),
328 mFadeInitial( true ),
329 mLoadedConnection( this ),
330 mFadeInDuration( 1.0f )
334 ImageActor::~ImageActor()
336 // ScopedConnection disconnects automatically
339 void ImageActor::OnImageSet( Image& image )
341 // observe image loaded
342 if( Dali::ResourceLoading == image.GetLoadingState() && ! image.GetFilename().empty() )
344 image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
348 // image already loaded, or generated
349 ImageLoaded( Dali::Image(&image) );
353 void ImageActor::SetNaturalSize( Image& image )
355 if( mUsingNaturalSize )
358 if( IsPixelAreaSet() )
360 PixelArea area(GetPixelArea());
361 size.width = area.width;
362 size.height = area.height;
366 size = image.GetNaturalSize();
369 mInternalSetSize = true;
371 mInternalSetSize = false;
375 void ImageActor::OnSizeSet( const Vector3& targetSize )
377 if( !mInternalSetSize )
379 mUsingNaturalSize = false;
383 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
385 mUsingNaturalSize = false;
388 void ImageActor::OnStageConnectionInternal()
392 mImageNext.OnStageConnect();
395 void ImageActor::OnStageDisconnectionInternal()
397 mImageNext.OnStageDisconnect();
400 void ImageActor::ImageLoaded( Dali::Image image )
402 DALI_ASSERT_DEBUG (image && "Image handle empty!");
404 // TODO: Handle case where image loading failed
406 // Need to keep mUploadedConnection connected as image may change later through Reload
407 // Note: Reloaded images may have changed size.
409 // Set the attachment's image once we know the image has loaded to prevent
410 // blank frames during load / reload.
411 mImageAttachment->SetImage( &GetImplementation( image ) );
413 // If size has never been set by application
414 if( mUsingNaturalSize )
416 // If a pixel area has been set, use this size
417 if( IsPixelAreaSet() )
419 const PixelArea& area = GetPixelArea();
420 mInternalSetSize = true;
421 SetSize(area.width, area.height);
422 mInternalSetSize = false;
426 mInternalSetSize = true;
427 SetSize( GetImplementation(image).GetNaturalSize() );
428 mInternalSetSize = false;
432 // fade in if required
436 void ImageActor::FadeIn()
438 // only fade in if enabled and newly displayed on screen
439 if( mFadeIn && mFadeInitial && ( mFadeInDuration > 0.0f ) )
441 // need to set opacity immediately to 0 otherwise child actors might get rendered
444 Dali::Image image = mImageAttachment->GetImage();
446 // Fade-in when on-stage & the image is loaded
449 image.GetLoadingState() == Dali::ResourceLoadingSucceeded)
451 // fire and forget animation; will clean up after it's finished
452 Dali::Animation animation = Dali::Animation::New( mFadeInDuration );
453 animation.OpacityTo( Dali::Actor( this ), 1.0f, AlphaFunctions::EaseOut );
455 mFadeInitial = false;
460 unsigned int ImageActor::GetDefaultPropertyCount() const
462 return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
465 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
467 RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
469 indices.reserve( indices.size() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT );
471 int index = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
472 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i, ++index )
474 indices.push_back( index );
478 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
480 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
482 return RenderableActor::IsDefaultPropertyWritable(index);
490 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
492 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
494 return RenderableActor::IsDefaultPropertyAnimatable(index);
502 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
504 if( index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT )
506 return RenderableActor::IsDefaultPropertyAConstraintInput(index);
508 return true; // Our properties can be used as input to constraints.
511 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
513 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
515 return RenderableActor::GetDefaultPropertyType(index);
519 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
521 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
523 return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index];
527 // index out-of-bounds
528 return Property::NONE;
533 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
535 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
537 return RenderableActor::GetDefaultPropertyName(index);
541 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
543 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
545 return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index];
549 // index out-of-bounds
550 static const std::string INVALID_PROPERTY_NAME;
551 return INVALID_PROPERTY_NAME;
556 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
558 Property::Index index = Property::INVALID_INDEX;
560 DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
562 // Look for name in current class' default properties
563 DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
564 if ( mDefaultImageActorPropertyLookup->end() != result )
566 index = result->second;
570 // If not found, check in base class
571 index = RenderableActor::GetDefaultPropertyIndex( name );
577 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
579 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
581 RenderableActor::SetDefaultProperty(index, propertyValue);
587 case Dali::ImageActor::PIXEL_AREA:
589 SetPixelArea(propertyValue.Get<Rect<int> >());
592 case Dali::ImageActor::FADE_IN:
594 SetFadeIn(propertyValue.Get<bool>());
597 case Dali::ImageActor::FADE_IN_DURATION:
599 SetFadeInDuration(propertyValue.Get<float>());
602 case Dali::ImageActor::STYLE:
604 SetStyle(StyleEnum(propertyValue.Get<std::string>()));
607 case Dali::ImageActor::BORDER:
609 SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
612 case Dali::ImageActor::IMAGE:
614 Dali::Image img = Scripting::NewImage( propertyValue );
617 SetImage( &GetImplementation(img) );
621 DALI_LOG_WARNING("Cannot create image from property value\n");
627 DALI_LOG_WARNING("Unknown property (%d)\n", index);
635 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
638 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
640 ret = RenderableActor::GetDefaultProperty(index);
646 case Dali::ImageActor::PIXEL_AREA:
648 Rect<int> r = GetPixelArea();
652 case Dali::ImageActor::FADE_IN:
657 case Dali::ImageActor::FADE_IN_DURATION:
659 ret = GetFadeInDuration();
662 case Dali::ImageActor::STYLE:
664 ret = StyleString(GetStyle());
667 case Dali::ImageActor::BORDER:
669 ret = GetNinePatchBorder();
672 case Dali::ImageActor::IMAGE:
675 Scripting::CreatePropertyMap( mImageAttachment->GetImage(), map );
676 ret = Property::Value( map );
681 DALI_LOG_WARNING("Unknown property (%d)\n", index);
691 } // namespace Internal