From cf58f2980b99438db9784a284e126d80893e6138 Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Fri, 30 Dec 2016 13:38:08 +0000 Subject: [PATCH] Automatic Control Clipping If the application sets to clip the children of a control, then this patch automatically creates a background visual which is used for clipping the children rather than the application writer having to do so. It only adds the background visual if no renderers or visuals have been added. Change-Id: I6e3c0c3c5459fc2cbc828daf3d01c7b0faf0a069 --- .../src/dali-toolkit/utc-Dali-Control.cpp | 116 ++++++++++++++++++++- .../src/dali-toolkit/utc-Dali-ControlImpl.cpp | 68 +++++++++++- dali-toolkit/public-api/controls/control-impl.cpp | 50 ++++++++- dali-toolkit/public-api/controls/control-impl.h | 6 ++ .../creating-custom-controls.md | 12 +++ 5 files changed, 248 insertions(+), 4 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp index 81a5781..93ee34e 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -607,3 +607,117 @@ int UtcDaliControlImplGetControlExtensionP(void) END_TEST; } + +int UtcDaliControlAutoClipping(void) +{ + ToolkitTestApplication application; + Control control = Control::New(); + + tet_infoline( "Test to see if a renderer gets added when we are clipping children" ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlAutoClippingN(void) +{ + ToolkitTestApplication application; + Control control = Control::New(); + control.SetProperty( Control::Property::BACKGROUND, Property::Map().Add( Visual::Property::TYPE, Visual::COLOR ) + .Add( ColorVisual::Property::MIX_COLOR, Color::RED ) ); + + tet_infoline( "Test to ensure that a renderer does NOT get added when we are clipping children and already have renderers/visuals" ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); // Only 1, not 2 + + // Ensure the background color is still RED rather than what's set by the automatic clipping + Property::Value value = control.GetProperty( Control::Property::BACKGROUND ); + Property::Map* map = value.GetMap(); + DALI_TEST_CHECK( map ); + Property::Value* colorValue = map->Find(ColorVisual::Property::MIX_COLOR ); + DALI_TEST_CHECK( colorValue ); + DALI_TEST_EQUALS( colorValue->Get< Vector4 >(), Color::RED, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlAutoClippingWhenAlreadyOnStage(void) +{ + ToolkitTestApplication application; + Control control = Control::New(); + + tet_infoline( "Test to see if a renderer gets added when we are clipping children and when already on stage" ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlAutoClippingWhenAlreadyOnStageN(void) +{ + ToolkitTestApplication application; + Control control = Control::New(); + control.SetProperty( Control::Property::BACKGROUND, Property::Map().Add( Visual::Property::TYPE, Visual::COLOR ) + .Add( ColorVisual::Property::MIX_COLOR, Color::RED ) ); + + tet_infoline( "Test to ensure that a renderer does NOT get added when we are clipping children and already have renderers/visuals and when already on stage" ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); // Still should be 1 + + // Ensure the background color is still RED rather than what's set by the automatic clipping + Property::Value value = control.GetProperty( Control::Property::BACKGROUND ); + Property::Map* map = value.GetMap(); + DALI_TEST_CHECK( map ); + Property::Value* colorValue = map->Find(ColorVisual::Property::MIX_COLOR ); + DALI_TEST_CHECK( colorValue ); + DALI_TEST_EQUALS( colorValue->Get< Vector4 >(), Color::RED, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp index 4a29efc..77c2436 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1351,3 +1351,69 @@ int UtcDaliControlImplRegisterTwoVisualsAndEnableOnlyOne(void) END_TEST; } +int UtcDaliControlImplAutoClippingWithVisuals(void) +{ + ToolkitTestApplication application; + + tet_infoline( "Test to ensure a renderer does NOT get added when we've already registered a visual which we haven't enabled" ); + + DummyControl control = DummyControl::New(); + DummyControlImpl& controlImpl = static_cast( control.GetImplementation() ); + + Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get(); + Toolkit::Visual::Base visual; + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::RED; + visual = visualFactory.CreateVisual( map ); + DALI_TEST_CHECK(visual); + controlImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual, false ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlImplAutoClippingWithVisualsAlreadyOnStage(void) +{ + ToolkitTestApplication application; + + tet_infoline( "Test to ensure a renderer does NOT get added when we've already registered a visual which we haven't enabled and we're already on the stage" ); + + DummyControl control = DummyControl::New(); + DummyControlImpl& controlImpl = static_cast( control.GetImplementation() ); + + Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get(); + Toolkit::Visual::Base visual; + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::RED; + visual = visualFactory.CreateVisual( map ); + DALI_TEST_CHECK(visual); + controlImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual, false ); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + Stage::GetCurrent().Add( control ); + + application.SendNotification(); + application.Render(); + + control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION ); + + END_TEST; +} diff --git a/dali-toolkit/public-api/controls/control-impl.cpp b/dali-toolkit/public-api/controls/control-impl.cpp index 5103060..c62684f 100644 --- a/dali-toolkit/public-api/controls/control-impl.cpp +++ b/dali-toolkit/public-api/controls/control-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,11 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS"); #endif +DALI_ENUM_TO_STRING_TABLE_BEGIN( CLIPPING_MODE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( ClippingMode, DISABLED ) +DALI_ENUM_TO_STRING_WITH_SCOPE( ClippingMode, CLIP_CHILDREN ) +DALI_ENUM_TO_STRING_TABLE_END( CLIPPING_MODE ) + /** * Struct used to store Visual within the control, index is a unique key for each visual. */ @@ -1149,16 +1155,33 @@ void Control::OnStageConnection( int depth ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection number of registered visuals(%d)\n", mImpl->mVisuals.Size() ); + Actor self( Self() ); + for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter!= mImpl->mVisuals.End(); iter++) { // Check whether the visual is empty and enabled if( (*iter)->visual && (*iter)->enabled ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection Setting visual(%d) on stage\n", (*iter)->index ); - Actor self( Self() ); Toolkit::GetImplementation((*iter)->visual).SetOnStage( self ); } } + + if( mImpl->mVisuals.Empty() && ! self.GetRendererCount() ) + { + Property::Value clippingValue = self.GetProperty( Actor::Property::CLIPPING_MODE ); + int clippingMode = ClippingMode::DISABLED; + if( clippingValue.Get( clippingMode ) ) + { + // Add a transparent background if we do not have any renderers or visuals so we clip our children + + if( clippingMode == ClippingMode::CLIP_CHILDREN ) + { + // Create a transparent background visual which will also get staged. + SetBackgroundColor( Color::TRANSPARENT ); + } + } + } } void Control::OnStageDisconnection() @@ -1197,6 +1220,29 @@ void Control::OnChildRemove(Actor& child) OnControlChildRemove( child ); } +void Control::OnPropertySet( Property::Index index, Property::Value propertyValue ) +{ + Actor self( Self() ); + if( index == Actor::Property::CLIPPING_MODE ) + { + // Only set the background if we're already on the stage and have no renderers or visuals + + if( mImpl->mVisuals.Empty() && ! self.GetRendererCount() && self.OnStage() ) + { + ClippingMode::Type clippingMode = ClippingMode::DISABLED; + if( Scripting::GetEnumerationProperty< ClippingMode::Type >( propertyValue, CLIPPING_MODE_TABLE, CLIPPING_MODE_TABLE_COUNT, clippingMode ) ) + { + // Add a transparent background if we do not have one so we clip children + + if( clippingMode == ClippingMode::CLIP_CHILDREN ) + { + SetBackgroundColor( Color::TRANSPARENT ); + } + } + } + } +} + void Control::OnSizeSet(const Vector3& targetSize) { Toolkit::Visual::Base visual = GetVisual( Toolkit::Control::Property::BACKGROUND ); diff --git a/dali-toolkit/public-api/controls/control-impl.h b/dali-toolkit/public-api/controls/control-impl.h index c21bdae..d850eb4 100644 --- a/dali-toolkit/public-api/controls/control-impl.h +++ b/dali-toolkit/public-api/controls/control-impl.h @@ -416,6 +416,12 @@ protected: // From CustomActorImpl, not to be used by application developers virtual void OnChildRemove( Actor& child ); /** + * @copydoc CustomActorImpl::OnPropertySet() + * @note If overridden, then an up-call to Control::OnChildRemove MUST be made at the end. + */ + virtual void OnPropertySet( Property::Index index, Property::Value propertyValue ); + + /** * @copydoc CustomActorImpl::OnSizeSet() * @note If overridden, then an up-call to Control::OnSizeSet MUST be made at the end. */ diff --git a/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md b/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md index 24620d8..54a0220 100644 --- a/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md +++ b/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md @@ -449,6 +449,18 @@ More information on size negotiation can be found [here](@ref size-negotiation-c ___________________________________________________________________________________________________ +### Clipping Support {#creating-controls-clipping} + +When an Actor is set to clip its children, the renderers have to be added manually in order to specify what its children need to clip to. +The Control base class automates the creation of the renderers/visuals when it is set to clip its children. + +This is only done if the application or custom control writer has not added any renderers to the Control or registered any visuals +(regardless of whether these visuals are enabled or not). + +If custom control writers want to define the clipping visuals themselves, then they should register all required visuals before the control is staged. + +___________________________________________________________________________________________________ + ### Other Features {#creating-controls-other} + [Background](@ref background) -- 2.7.4