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();
114 // Note, if theImage is empty, the nine-patch image was not loaded
117 // Create the attachment
118 actor->mImageAttachment = ImageAttachment::New( *actor->mNode, theImage.Get() );
119 actor->Attach( *actor->mImageAttachment );
121 // Adjust the actor's size
124 actor->mImageNext.Set( theImage.Get(), false );
125 actor->OnImageSet( *theImage );
126 actor->SetNaturalSize( *theImage );
129 if( ninePatchImage != NULL )
131 actor->SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
132 Vector4 border = ninePatchImage->GetStretchBorders();
133 actor->SetNinePatchBorder( border, true );
140 ImageActorPtr ImageActor::New( Image* image, const PixelArea& pixelArea )
143 ImageActorPtr actor = New( image );
144 // then set the pixel area
145 actor->mImageAttachment->SetPixelArea( pixelArea );
149 void ImageActor::OnInitialize()
151 if(ImageActor::mFirstInstance)
153 mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
154 const int start = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
155 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
157 (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
159 ImageActor::mFirstInstance = false;
163 void ImageActor::SetImage( Image* image )
165 Image* currentImage = static_cast<Image*>(mImageAttachment->GetImage().GetObjectPtr());
166 // early exit if it's the same image
167 if ( currentImage == image || mImageNext.Get() == image )
172 mLoadedConnection.DisconnectAll();
174 ImagePtr imagePtr( image );
176 // Automatically convert nine-patch images to cropped bitmap
177 NinePatchImage* ninePatchImage = NinePatchImage::GetNinePatchImage( image );
180 imagePtr = ninePatchImage->CreateCroppedBitmapImage();
183 mImageNext.Set( imagePtr.Get(), OnStage() );
187 SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
188 SetNinePatchBorder( ninePatchImage->GetStretchBorders(), true );
193 mImageAttachment->SetImage( NULL );
197 // don't disconnect currently shown image until we made sure that the new one is loaded
198 OnImageSet( *imagePtr.Get() );
202 Dali::Image ImageActor::GetImage()
204 return mImageAttachment->GetImage();
207 void ImageActor::SetToNaturalSize()
209 mUsingNaturalSize = true;
210 Dali::Image image = mImageAttachment->GetImage();
214 SetNaturalSize( GetImplementation(image) );
218 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
220 mImageAttachment->SetPixelArea( pixelArea );
222 if( mUsingNaturalSize )
224 mInternalSetSize = true;
225 SetSize(pixelArea.width, pixelArea.height);
226 mInternalSetSize = false;
230 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
232 return mImageAttachment->GetPixelArea();
235 bool ImageActor::IsPixelAreaSet() const
237 return mImageAttachment->IsPixelAreaSet();
240 void ImageActor::ClearPixelArea()
242 mImageAttachment->ClearPixelArea();
244 if( mUsingNaturalSize )
246 Dali::Image image = mImageAttachment->GetImage();
249 mInternalSetSize = true;
250 SetSize(GetImplementation(image).GetNaturalSize());
251 mInternalSetSize = false;
256 void ImageActor::SetStyle( Style style )
258 mImageAttachment->SetStyle( style );
261 ImageActor::Style ImageActor::GetStyle() const
263 return mImageAttachment->GetStyle();
266 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
268 mImageAttachment->SetNinePatchBorder( border, inPixels );
271 Vector4 ImageActor::GetNinePatchBorder() const
273 return mImageAttachment->GetNinePatchBorder();
276 void ImageActor::SetFadeIn( bool enableFade )
278 mFadeIn = enableFade;
281 bool ImageActor::GetFadeIn() const
286 void ImageActor::SetFadeInDuration( float durationSeconds )
288 mFadeInDuration = durationSeconds;
291 float ImageActor::GetFadeInDuration() const
293 return mFadeInDuration;
296 ImageAttachment& ImageActor::GetImageAttachment()
298 return *mImageAttachment;
301 Vector2 ImageActor::GetCurrentImageSize() const
306 // get the texture size / pixel area if only a subset of it is displayed
307 if( IsPixelAreaSet() )
309 PixelArea area(GetPixelArea());
310 return Vector2(area.width, area.height );
314 return Vector2( GetCurrentSize() );
318 RenderableAttachment& ImageActor::GetRenderableAttachment() const
320 DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
321 return *mImageAttachment;
324 ImageActor::ImageActor()
326 mUsingNaturalSize(true),
327 mInternalSetSize(false),
329 mFadeInitial( true ),
330 mLoadedConnection( this ),
331 mFadeInDuration( 1.0f )
335 ImageActor::~ImageActor()
337 // ScopedConnection disconnects automatically
340 void ImageActor::OnImageSet( Image& image )
342 // observe image loaded
343 if( Dali::ResourceLoading == image.GetLoadingState() && ! image.GetFilename().empty() )
345 image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
349 // image already loaded, or generated
350 ImageLoaded( Dali::Image(&image) );
354 void ImageActor::SetNaturalSize( Image& image )
356 if( mUsingNaturalSize )
359 if( IsPixelAreaSet() )
361 PixelArea area(GetPixelArea());
362 size.width = area.width;
363 size.height = area.height;
367 size = image.GetNaturalSize();
370 mInternalSetSize = true;
372 mInternalSetSize = false;
376 void ImageActor::OnSizeSet( const Vector3& targetSize )
378 if( !mInternalSetSize )
380 mUsingNaturalSize = false;
384 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
386 mUsingNaturalSize = false;
389 void ImageActor::OnStageConnectionInternal()
393 mImageNext.OnStageConnect();
396 void ImageActor::OnStageDisconnectionInternal()
398 mImageNext.OnStageDisconnect();
401 void ImageActor::ImageLoaded( Dali::Image image )
403 DALI_ASSERT_DEBUG (image && "Image handle empty!");
405 // TODO: Handle case where image loading failed
407 // Need to keep mUploadedConnection connected as image may change later through Reload
408 // Note: Reloaded images may have changed size.
410 // Set the attachment's image once we know the image has loaded to prevent
411 // blank frames during load / reload.
412 mImageAttachment->SetImage( &GetImplementation( image ) );
414 // If size has never been set by application
415 if( mUsingNaturalSize )
417 // If a pixel area has been set, use this size
418 if( IsPixelAreaSet() )
420 const PixelArea& area = GetPixelArea();
421 mInternalSetSize = true;
422 SetSize(area.width, area.height);
423 mInternalSetSize = false;
427 mInternalSetSize = true;
428 SetSize( GetImplementation(image).GetNaturalSize() );
429 mInternalSetSize = false;
433 // fade in if required
437 void ImageActor::FadeIn()
439 // only fade in if enabled and newly displayed on screen
440 if( mFadeIn && mFadeInitial && ( mFadeInDuration > 0.0f ) )
442 // need to set opacity immediately to 0 otherwise child actors might get rendered
445 Dali::Image image = mImageAttachment->GetImage();
447 // Fade-in when on-stage & the image is loaded
450 image.GetLoadingState() == Dali::ResourceLoadingSucceeded)
452 // fire and forget animation; will clean up after it's finished
453 Dali::Animation animation = Dali::Animation::New( mFadeInDuration );
454 animation.OpacityTo( Dali::Actor( this ), 1.0f, AlphaFunctions::EaseOut );
456 mFadeInitial = false;
461 unsigned int ImageActor::GetDefaultPropertyCount() const
463 return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
466 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
468 RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
470 indices.reserve( indices.size() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT );
472 int index = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
473 for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i, ++index )
475 indices.push_back( index );
479 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
481 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
483 return RenderableActor::IsDefaultPropertyWritable(index);
491 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
493 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
495 return RenderableActor::IsDefaultPropertyAnimatable(index);
503 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
505 if( index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT )
507 return RenderableActor::IsDefaultPropertyAConstraintInput(index);
509 return true; // Our properties can be used as input to constraints.
512 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
514 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
516 return RenderableActor::GetDefaultPropertyType(index);
520 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
522 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
524 return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index];
528 // index out-of-bounds
529 return Property::NONE;
534 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
536 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
538 return RenderableActor::GetDefaultPropertyName(index);
542 index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
544 if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
546 return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index];
550 // index out-of-bounds
551 static const std::string INVALID_PROPERTY_NAME;
552 return INVALID_PROPERTY_NAME;
557 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
559 Property::Index index = Property::INVALID_INDEX;
561 DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
563 // Look for name in current class' default properties
564 DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
565 if ( mDefaultImageActorPropertyLookup->end() != result )
567 index = result->second;
571 // If not found, check in base class
572 index = RenderableActor::GetDefaultPropertyIndex( name );
578 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
580 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
582 RenderableActor::SetDefaultProperty(index, propertyValue);
588 case Dali::ImageActor::PIXEL_AREA:
590 SetPixelArea(propertyValue.Get<Rect<int> >());
593 case Dali::ImageActor::FADE_IN:
595 SetFadeIn(propertyValue.Get<bool>());
598 case Dali::ImageActor::FADE_IN_DURATION:
600 SetFadeInDuration(propertyValue.Get<float>());
603 case Dali::ImageActor::STYLE:
605 SetStyle(StyleEnum(propertyValue.Get<std::string>()));
608 case Dali::ImageActor::BORDER:
610 SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
613 case Dali::ImageActor::IMAGE:
615 Dali::Image img = Scripting::NewImage( propertyValue );
618 SetImage( &GetImplementation(img) );
622 DALI_LOG_WARNING("Cannot create image from property value\n");
628 DALI_LOG_WARNING("Unknown property (%d)\n", index);
636 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
639 if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
641 ret = RenderableActor::GetDefaultProperty(index);
647 case Dali::ImageActor::PIXEL_AREA:
649 Rect<int> r = GetPixelArea();
653 case Dali::ImageActor::FADE_IN:
658 case Dali::ImageActor::FADE_IN_DURATION:
660 ret = GetFadeInDuration();
663 case Dali::ImageActor::STYLE:
665 ret = StyleString(GetStyle());
668 case Dali::ImageActor::BORDER:
670 ret = GetNinePatchBorder();
673 case Dali::ImageActor::IMAGE:
676 Scripting::CreatePropertyMap( mImageAttachment->GetImage(), map );
677 ret = Property::Value( map );
682 DALI_LOG_WARNING("Unknown property (%d)\n", index);
692 } // namespace Internal