ADD_CUSTOM_TARGET(
test_check_built_in_created
ALL
- COMMAND ${SHADER_GENERATOR} . ${GENERATED_FOLDER} | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded"
+ COMMAND rm -rf ${GENERATED_FOLDER}/check_built_in
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/check_built_in/generated | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded"
VERBATIM)
ADD_CUSTOM_TARGET(
test_check_built_in_not_created
ALL
- COMMAND ${SHADER_GENERATOR} --skip . ${GENERATED_FOLDER} | grep builtin-shader > /dev/null 2>&1 || echo "test_check_built_in_not_created Succeeded"
+ COMMAND rm -rf ${GENERATED_FOLDER}/skip_built_in
+ COMMAND ${SHADER_GENERATOR} --skip ${SHADER_FOLDER} ${GENERATED_FOLDER}/skip_built_in/generated | grep builtin-shader > /dev/null 2>&1 && exit 1 || echo "test_check_built_in_not_created Succeeded"
VERBATIM)
ADD_CUSTOM_TARGET(
test_frag_correct
ALL
- COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded"
+ COMMAND rm -rf ${GENERATED_FOLDER}/frag_correct
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/frag_correct/generated | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded"
VERBATIM)
ADD_CUSTOM_TARGET(
test_vert_correct
ALL
- COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded"
+ COMMAND rm -rf ${GENERATED_FOLDER}/vert_correct
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/vert_correct/generated | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded"
VERBATIM)
ADD_CUSTOM_TARGET(
test_def_correct
ALL
- COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded"
+ COMMAND rm -rf ${GENERATED_FOLDER}/def_correct
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/def_correct/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded"
+ VERBATIM)
+ADD_CUSTOM_TARGET(
+ test_no_overwrite
+ ALL
+ COMMAND rm -rf ${GENERATED_FOLDER}/no_overwrite
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/no_overwrite/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1
+ COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/no_overwrite/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && exit 1 || echo "test_no_overwrite Succeeded"
VERBATIM)
// test harness headers before dali headers.
#include <dali-toolkit-test-suite-utils.h>
-#include <dali.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali.h>
-#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
+#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/atspi-interfaces/accessible.h>
#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
ToolkitTestApplication application;
auto check_box_button = Toolkit::CheckBoxButton::New();
- auto q = Dali::Accessibility::Accessible::Get( check_box_button );
- DALI_TEST_CHECK( q );
+ auto q = Dali::Accessibility::Accessible::Get(check_box_button);
+ DALI_TEST_CHECK(q);
auto states = q->GetStates();
- DALI_TEST_EQUALS( (int) states[ Dali::Accessibility::State::SELECTABLE ], (int) true, TEST_LOCATION );
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SELECTABLE], (int)true, TEST_LOCATION);
END_TEST;
}
auto check_box_button = Toolkit::CheckBoxButton::New();
//check_box_button.SetLabelText( "button" );
check_box_button.SetProperty(Toolkit::Button::Property::LABEL, "button");
- auto q = Dali::Accessibility::Accessible::Get( check_box_button );
- DALI_TEST_CHECK( q );
- DALI_TEST_EQUALS( q->GetName(), "button", TEST_LOCATION );
+ auto q = Dali::Accessibility::Accessible::Get(check_box_button);
+ DALI_TEST_CHECK(q);
+ DALI_TEST_EQUALS(q->GetName(), "button", TEST_LOCATION);
END_TEST;
}
parentButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
parentButton.SetProperty(Actor::Property::POSITION, Dali::Vector2(0.0f, 0.0f));
parentButton.SetProperty(Actor::Property::SIZE, Dali::Vector2(200.0f, 200.0f));
- application.GetScene().Add( parentButton );
+ application.GetScene().Add(parentButton);
// Toatally inside of parent
auto buttonA = Toolkit::PushButton::New();
auto buttonC = Toolkit::PushButton::New();
buttonC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
buttonC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
- buttonC.SetProperty(Actor::Property::POSITION, Dali::Vector2(100.0f,100.0f));
+ buttonC.SetProperty(Actor::Property::POSITION, Dali::Vector2(100.0f, 100.0f));
buttonC.SetProperty(Actor::Property::SIZE, Dali::Vector2(200.0f, 200.0f));
parentButton.Add(buttonC);
auto q = Dali::Accessibility::Accessible::Get(buttonA);
DALI_TEST_CHECK(q);
auto states = q->GetStates();
- DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
q = Dali::Accessibility::Accessible::Get(buttonB);
DALI_TEST_CHECK(q);
states = q->GetStates();
- DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
q = Dali::Accessibility::Accessible::Get(buttonC);
DALI_TEST_CHECK(q);
states = q->GetStates();
- DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
// Make SHOWING object invisible
buttonC.SetProperty(Actor::Property::VISIBLE, false);
application.Render(16);
states = q->GetStates();
- DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) false, TEST_LOCATION);
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)false, TEST_LOCATION);
// Make SHOWING parent invisible
parentButton.SetProperty(Actor::Property::VISIBLE, false);
q = Dali::Accessibility::Accessible::Get(buttonA);
DALI_TEST_CHECK(q);
states = q->GetStates();
- DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) false, TEST_LOCATION);
+ DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)false, TEST_LOCATION);
END_TEST;
}
END_TEST;
}
+
+int utcDaliImgSrc(void)
+{
+ ToolkitTestApplication application;
+ const std::string imageSrcKey = "imgSrc";
+ // Check that imgSrc is NOT added for non-image view w/ no additional property
+ {
+ const auto checkBoxButton = Toolkit::CheckBoxButton::New();
+ const auto controlAccessible = Dali::Accessibility::Accessible::Get(checkBoxButton);
+ auto attributes = controlAccessible->GetAttributes();
+ DALI_TEST_CHECK(attributes.find(imageSrcKey) == attributes.end());
+ }
+
+ // Check that imgSrc is NOT added for non-image view w/ additional properties
+ {
+ const auto textLabel = Toolkit::TextLabel::New("Hello");
+ const auto controlAccessible = Dali::Accessibility::Accessible::Get(textLabel);
+ auto attributes = controlAccessible->GetAttributes();
+ DALI_TEST_CHECK(attributes.find(imageSrcKey) == attributes.end());
+ }
+
+ // Check that imgSrc is added for image view w/ Url
+ {
+ const std::string imagePath = "gallery-small-1.jpg";
+ const auto imageView = Toolkit::ImageView::New(imagePath);
+ const auto controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+ auto attributes = controlAccessible->GetAttributes();
+ DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+ DALI_TEST_EQUALS(attributes[imageSrcKey], imagePath, TEST_LOCATION);
+ }
+
+ // Check that imgSrc is added for image view w/ imageMap; single url case
+ {
+ const std::string imagePathForImageMap = "icon-edit.png";
+ Property::Map imageMap;
+ imageMap[Toolkit::ImageVisual::Property::URL] = imagePathForImageMap;
+ imageMap[Toolkit::ImageVisual::Property::RELEASE_POLICY] = Toolkit::ImageVisual::ReleasePolicy::DETACHED;
+
+ auto imageView = Toolkit::ImageView::New();
+ imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
+
+ const auto controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+ auto attributes = controlAccessible->GetAttributes();
+ DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+ DALI_TEST_EQUALS(attributes[imageSrcKey], imagePathForImageMap, TEST_LOCATION);
+ }
+
+ // Check that imgSrc is added for image view w/ imageMap; url array returns first element
+ {
+ const std::string image1 = "application-icon-20.png";
+ const std::string image2 = "application-icon-21.png";
+ Property::Map imageMap;
+ Property::Array urls{image1, image2};
+ imageMap[Toolkit::ImageVisual::Property::URL] = urls;
+ imageMap[Toolkit::ImageVisual::Property::RELEASE_POLICY] = Toolkit::ImageVisual::ReleasePolicy::DETACHED;
+
+ auto imageView = Toolkit::ImageView::New();
+ imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
+
+ const auto controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+ auto attributes = controlAccessible->GetAttributes();
+ DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+ DALI_TEST_EQUALS(attributes[imageSrcKey], image1, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
#include <dali/devel-api/atspi-interfaces/accessible.h>
+#include <dali/devel-api/atspi-interfaces/component.h>
#include <dali/devel-api/atspi-interfaces/value.h>
#include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
+#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h>
#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
using namespace Dali::Accessibility;
int utcDaliAccessibilityProgressBarGetSetCurrent(void)
{
ToolkitTestApplication application;
+ Dali::Accessibility::TestEnableSC(true);
Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New();
auto q = Dali::Accessibility::Accessible::Get(progress_bar);
auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
DALI_TEST_CHECK( x );
+ DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION );
DALI_TEST_EQUALS( x->GetCurrent(), 0.25, TEST_LOCATION );
DALI_TEST_EQUALS( x->GetValueText().empty(), true, TEST_LOCATION ); // not implemented
+ Dali::Accessibility::TestEnableSC(false);
END_TEST;
}
int utcDaliAccessibilityScrollBarGetSetCurrent(void)
{
ToolkitTestApplication application;
+ Dali::Accessibility::TestEnableSC(true);
// Create a source actor that owns the scroll properties required by the scroll bar
Actor sourceActor = Actor::New();
auto q = Dali::Accessibility::Accessible::Get(scroll_bar);
auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
DALI_TEST_CHECK( x );
+ DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 1000.0 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 50.0 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
DALI_TEST_EQUALS( x->GetValueText().empty(), true, TEST_LOCATION ); // not implemented
+ Dali::Accessibility::TestEnableSC(false);
END_TEST;
}
int utcDaliAccessibilitySliderGetSetCurrent(void)
{
ToolkitTestApplication application;
+ Dali::Accessibility::TestEnableSC(true);
Toolkit::Slider slider = Toolkit::Slider::New();
auto q = Dali::Accessibility::Accessible::Get(slider);
auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
DALI_TEST_CHECK( x );
+ DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION );
DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION );
// depending if the new value is greater/less than current value
DALI_TEST_CHECK( x->SetCurrent( 0.2f ) );
DALI_TEST_EQUALS( static_cast<float>( x->GetCurrent() ), marks[2].Get<float>(), TEST_LOCATION );
+
+ Dali::Accessibility::TestEnableSC(false);
END_TEST;
}
END_TEST;
}
+
+int UtcDaliTextControllerMultipleInsert(void)
+{
+ tet_infoline(" UtcDaliTextControllerMultipleInsert");
+ ToolkitTestApplication application;
+
+ // Creates a text controller.
+ ControllerPtr controller = Controller::New();
+
+ ConfigureTextField(controller);
+
+ // Get the implementation of the text controller
+ Controller::Impl& mImpl = Controller::Impl::GetImplementation(*controller.Get());
+
+ DALI_TEST_EQUALS(EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION);
+
+ InputMethodContext inputMethodContext = InputMethodContext::New();
+
+ // When maid thread is busy, multiple event might be executed.
+ InputMethodContext::EventData imfEvent1 = InputMethodContext::EventData(InputMethodContext::PRE_EDIT, "A", 0, 1);
+ InputMethodContext::EventData imfEvent2 = InputMethodContext::EventData(InputMethodContext::PRE_EDIT, "AAAAA", 0, 5);
+ controller->OnInputMethodContextEvent(inputMethodContext, imfEvent1);
+ controller->OnInputMethodContextEvent(inputMethodContext, imfEvent2);
+
+ // Perform a relayout
+ const Size size(application.GetScene().GetSize());
+
+ application.SendNotification();
+ application.Render();
+
+ controller->Relayout(size);
+
+ std::string text;
+ controller->GetText(text);
+
+ DALI_TEST_EQUALS("AAAAA", text, TEST_LOCATION);
+
+ tet_result(TET_PASS);
+
+ END_TEST;
+}
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include "dummy-control.h"
#include <dali-toolkit/dali-toolkit.h>
-#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
namespace Dali
{
-
namespace Toolkit
{
-
DummyControl::DummyControl()
{
}
DummyControl::DummyControl(const DummyControl& control)
-: Control( control )
+: Control(control)
{
}
{
}
-DummyControl DummyControl::DownCast( BaseHandle handle )
+DummyControl DummyControl::DownCast(BaseHandle handle)
{
return Control::DownCast<DummyControl, DummyControlImpl>(handle);
}
DummyControl& DummyControl::operator=(const DummyControl& control)
{
- Control::operator=( control );
+ Control::operator=(control);
return *this;
}
// Used to test signal connections
-void DummyControlImpl::CustomSlot1( Actor actor )
+void DummyControlImpl::CustomSlot1(Actor actor)
{
mCustomSlot1Called = true;
}
-namespace {
-
+namespace
+{
BaseHandle Create()
{
return DummyControlImpl::New();
}
-DALI_TYPE_REGISTRATION_BEGIN( Toolkit::DummyControl, Toolkit::Control, Create );
+DALI_TYPE_REGISTRATION_BEGIN(Toolkit::DummyControl, Toolkit::Control, Create);
DALI_TYPE_REGISTRATION_END()
Dali::PropertyRegistration dummyControlVisualProperty01(
- typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+ typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
Dali::PropertyRegistration dummyControlVisualProperty02(
- typeRegistration, "testVisual2", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+ typeRegistration, "testVisual2", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
Dali::PropertyRegistration dummyControlVisualProperty03(
- typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+ typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
Dali::PropertyRegistration dummyControlVisualProperty04(
- typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+ typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
Dali::PropertyRegistration dummyControlVisualProperty05(
- typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+ typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
-}
+} // namespace
DummyControl DummyControlImpl::New()
{
- IntrusivePtr< DummyControlImpl > impl = new DummyControlImpl;
- DummyControl control( *impl );
+ IntrusivePtr<DummyControlImpl> impl = new DummyControlImpl;
+ DummyControl control(*impl);
impl->Initialize();
return control;
}
DummyControlImpl::DummyControlImpl()
-: Control( ControlBehaviour() ),
+: Control(ControlBehaviour()),
mCustomSlot1Called(false)
{
}
{
}
-void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual )
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual)
+{
+ DevelControl::RegisterVisual(*this, index, visual);
+
+ VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+ if(iter == mRegisteredVisualIndices.end())
+ {
+ mRegisteredVisualIndices.push_back(index);
+ }
+}
+
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, bool enabled)
{
- DevelControl::RegisterVisual( *this, index, visual );
+ DevelControl::RegisterVisual(*this, index, visual, enabled);
- VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
- if( iter == mRegisteredVisualIndices.end() )
+ VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+ if(iter == mRegisteredVisualIndices.end())
{
mRegisteredVisualIndices.push_back(index);
}
}
-void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled )
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, int depthIndex)
{
- DevelControl::RegisterVisual( *this, index, visual, enabled );
+ DevelControl::RegisterVisual(*this, index, visual, depthIndex);
- VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
- if( iter == mRegisteredVisualIndices.end() )
+ VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+ if(iter == mRegisteredVisualIndices.end())
{
mRegisteredVisualIndices.push_back(index);
}
}
-void DummyControlImpl::UnregisterVisual( Property::Index index )
+void DummyControlImpl::UnregisterVisual(Property::Index index)
{
- DevelControl::UnregisterVisual( *this, index );
+ DevelControl::UnregisterVisual(*this, index);
- VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
- if( iter != mRegisteredVisualIndices.end() )
+ VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+ if(iter != mRegisteredVisualIndices.end())
{
mRegisteredVisualIndices.erase(iter);
}
}
-Toolkit::Visual::Base DummyControlImpl::GetVisual( Property::Index index )
+Toolkit::Visual::Base DummyControlImpl::GetVisual(Property::Index index)
{
- return DevelControl::GetVisual( *this, index );
+ return DevelControl::GetVisual(*this, index);
}
-void DummyControlImpl::EnableVisual( Property::Index index, bool enabled )
+void DummyControlImpl::EnableVisual(Property::Index index, bool enabled)
{
- DevelControl::EnableVisual( *this, index, enabled );
+ DevelControl::EnableVisual(*this, index, enabled);
}
-bool DummyControlImpl::IsVisualEnabled( Property::Index index )
+bool DummyControlImpl::IsVisualEnabled(Property::Index index)
{
- return DevelControl::IsVisualEnabled( *this, index );
+ return DevelControl::IsVisualEnabled(*this, index);
}
-Animation DummyControlImpl::CreateTransition( const Toolkit::TransitionData& transition )
+Animation DummyControlImpl::CreateTransition(const Toolkit::TransitionData& transition)
{
- return DevelControl::CreateTransition( *this, transition );
+ return DevelControl::CreateTransition(*this, transition);
}
-void DummyControlImpl::DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes )
+void DummyControlImpl::DoAction(Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes)
{
- DummyControl control( *this );
- DevelControl::DoAction( control, index, action, attributes);
+ DummyControl control(*this);
+ DevelControl::DoAction(control, index, action, attributes);
}
-void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value )
+void DummyControlImpl::SetProperty(BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value)
{
- Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
- DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
+ Toolkit::DummyControl control = Toolkit::DummyControl::DownCast(Dali::BaseHandle(object));
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
switch(index)
{
case Toolkit::DummyControl::Property::LABEL_VISUAL:
{
const Property::Map* map = value.GetMap();
- if( map != NULL )
+ if(map != NULL)
{
VisualFactory visualFactory = VisualFactory::Get();
- Visual::Base visual = visualFactory.CreateVisual(*map);
+ Visual::Base visual = visualFactory.CreateVisual(*map);
dummyImpl.RegisterVisual(index, visual);
}
break;
}
}
-Property::Value DummyControlImpl::GetProperty( BaseObject* object, Dali::Property::Index propertyIndex )
+Property::Value DummyControlImpl::GetProperty(BaseObject* object, Dali::Property::Index propertyIndex)
{
- Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
- DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>( control.GetImplementation() );
+ Toolkit::DummyControl control = Toolkit::DummyControl::DownCast(Dali::BaseHandle(object));
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
- Visual::Base visual = dummyImpl.GetVisual( propertyIndex );
+ Visual::Base visual = dummyImpl.GetVisual(propertyIndex);
Property::Map map;
- if( visual )
+ if(visual)
{
- visual.CreatePropertyMap( map );
+ visual.CreatePropertyMap(map);
}
Dali::Property::Value value = map;
return value;
}
-
Toolkit::DummyControl Impl::DummyControl::New()
{
- IntrusivePtr< Toolkit::Impl::DummyControl > impl = new Toolkit::Impl::DummyControl;
- Toolkit::DummyControl control( *impl );
+ IntrusivePtr<Toolkit::Impl::DummyControl> impl = new Toolkit::Impl::DummyControl;
+ Toolkit::DummyControl control(*impl);
impl->Initialize();
return control;
}
++destructorCount;
}
-void Impl::DummyControl::OnInitialize() { initializeCalled = true; }
-bool Impl::DummyControl::OnAccessibilityActivated() { activatedCalled = true; return true; }
-bool Impl::DummyControl::OnAccessibilityValueChange( bool isIncrease )
+void Impl::DummyControl::OnInitialize()
+{
+ initializeCalled = true;
+}
+bool Impl::DummyControl::OnAccessibilityActivated()
{
- onAccValueChangeCalled = true; return true;
+ activatedCalled = true;
+ return true;
+}
+bool Impl::DummyControl::OnAccessibilityValueChange(bool isIncrease)
+{
+ onAccValueChangeCalled = true;
+ return true;
}
-void Impl::DummyControl::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+void Impl::DummyControl::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
{
themeChangeCalled = change == StyleChange::THEME_CHANGE;
- fontChangeCalled = change == StyleChange::DEFAULT_FONT_SIZE_CHANGE;
-}
-void Impl::DummyControl::OnPinch(const PinchGesture& pinch) { pinchCalled = true; }
-void Impl::DummyControl::OnPan(const PanGesture& pan) { panCalled = true; }
-void Impl::DummyControl::OnTap(const TapGesture& tap) { tapCalled = true; }
-void Impl::DummyControl::OnLongPress(const LongPressGesture& longPress) { longPressCalled = true; }
-void Impl::DummyControl::OnSceneConnection( int depth ) { Control::OnSceneConnection( depth ); stageConnectionCalled = true; }
-void Impl::DummyControl::OnSceneDisconnection() { stageDisconnectionCalled = true; Control::OnSceneDisconnection(); }
-void Impl::DummyControl::OnChildAdd(Actor& child) { childAddCalled = true; }
-void Impl::DummyControl::OnChildRemove(Actor& child) { childRemoveCalled = true; }
-void Impl::DummyControl::OnSizeSet(const Vector3& targetSize) { Control::OnSizeSet( targetSize ); sizeSetCalled = true; }
-void Impl::DummyControl::OnSizeAnimation(Animation& animation, const Vector3& targetSize) { Control::OnSizeAnimation( animation, targetSize ); sizeAnimationCalled = true; }
-bool Impl::DummyControl::OnKeyEvent(const KeyEvent& event) { keyEventCalled = true; return false;}
+ fontChangeCalled = change == StyleChange::DEFAULT_FONT_SIZE_CHANGE;
+}
+void Impl::DummyControl::OnPinch(const PinchGesture& pinch)
+{
+ pinchCalled = true;
+}
+void Impl::DummyControl::OnPan(const PanGesture& pan)
+{
+ panCalled = true;
+}
+void Impl::DummyControl::OnTap(const TapGesture& tap)
+{
+ tapCalled = true;
+}
+void Impl::DummyControl::OnLongPress(const LongPressGesture& longPress)
+{
+ longPressCalled = true;
+}
+void Impl::DummyControl::OnSceneConnection(int depth)
+{
+ Control::OnSceneConnection(depth);
+ stageConnectionCalled = true;
+}
+void Impl::DummyControl::OnSceneDisconnection()
+{
+ stageDisconnectionCalled = true;
+ Control::OnSceneDisconnection();
+}
+void Impl::DummyControl::OnChildAdd(Actor& child)
+{
+ childAddCalled = true;
+}
+void Impl::DummyControl::OnChildRemove(Actor& child)
+{
+ childRemoveCalled = true;
+}
+void Impl::DummyControl::OnSizeSet(const Vector3& targetSize)
+{
+ Control::OnSizeSet(targetSize);
+ sizeSetCalled = true;
+}
+void Impl::DummyControl::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
+{
+ Control::OnSizeAnimation(animation, targetSize);
+ sizeAnimationCalled = true;
+}
+bool Impl::DummyControl::OnKeyEvent(const KeyEvent& event)
+{
+ keyEventCalled = true;
+ return false;
+}
void Impl::DummyControl::OnKeyInputFocusGained()
{
if(this->HasKeyInputFocus())
}
}
-void Impl::DummyControl::SetLayout( Property::Index visualIndex, Property::Map& map )
+void Impl::DummyControl::SetLayout(Property::Index visualIndex, Property::Map& map)
{
- Property::Value value( map );
+ Property::Value value(map);
mLayouts[visualIndex] = value;
}
-void Impl::DummyControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
+void Impl::DummyControl::OnRelayout(const Vector2& size, RelayoutContainer& container)
{
- if ( mRelayoutCallback )
+ if(mRelayoutCallback)
{
- mRelayoutCallback( size ); // Execute callback if set
+ mRelayoutCallback(size); // Execute callback if set
}
Property::Map emptyMap;
- for( VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end() ; ++iter )
+ for(VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end(); ++iter)
{
- Visual::Base visual = GetVisual(*iter);
- Property::Value value = mLayouts[*iter];
- Property::Map* map = NULL;
+ Visual::Base visual = GetVisual(*iter);
+ Property::Value value = mLayouts[*iter];
+ Property::Map* map = NULL;
- if( value.GetType() != Property::NONE )
+ if(value.GetType() != Property::NONE)
{
map = value.GetMap();
}
- if( map == NULL )
+ if(map == NULL)
{
map = &emptyMap;
}
- visual.SetTransformAndSize( *map, size );
+ visual.SetTransformAndSize(*map, size);
}
}
-void Impl::DummyControl::SetRelayoutCallback( RelayoutCallbackFunc callback )
+void Impl::DummyControl::SetRelayoutCallback(RelayoutCallbackFunc callback)
{
mRelayoutCallback = callback;
}
{
Vector2 currentSize;
- for( auto elem : mRegisteredVisualIndices )
+ for(auto elem : mRegisteredVisualIndices)
{
- Vector2 naturalSize;
+ Vector2 naturalSize;
Visual::Base visual = GetVisual(elem);
- visual.GetNaturalSize( naturalSize );
- currentSize.width = std::max( naturalSize.width, currentSize.width );
- currentSize.height = std::max( naturalSize.height, currentSize.height );
+ visual.GetNaturalSize(naturalSize);
+ currentSize.width = std::max(naturalSize.width, currentSize.width);
+ currentSize.height = std::max(naturalSize.height, currentSize.height);
}
- return Vector3( currentSize );
+ return Vector3(currentSize);
}
-
-
-DummyControl DummyControl::New( bool override )
+DummyControl DummyControl::New(bool override)
{
DummyControl control;
- if (override)
+ if(override)
{
control = Impl::DummyControl::New();
}
return control;
}
-DummyControl::DummyControl( DummyControlImpl& implementation )
-: Control( implementation )
+DummyControl::DummyControl(DummyControlImpl& implementation)
+: Control(implementation)
{
}
-DummyControl::DummyControl( Dali::Internal::CustomActor* internal )
-: Control( internal )
+DummyControl::DummyControl(Dali::Internal::CustomActor* internal)
+: Control(internal)
{
VerifyCustomActorPointer<DummyControlImpl>(internal);
}
#define DALI_TOOLKIT_TEST_DUMMY_CONTROL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
namespace Dali
{
-
namespace Toolkit
{
-
class DummyControlImpl;
class TransitionData;
enum PropertyRange
{
PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
- PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property index
+ PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property index
};
struct Property
DummyControl(const DummyControl& control);
~DummyControl();
- static DummyControl New( bool override = false );
-
- static DummyControl DownCast( BaseHandle handle );
+ static DummyControl New(bool override = false);
+ static DummyControl DownCast(BaseHandle handle);
DummyControl& operator=(const DummyControl& control);
public: // Not intended for application developers
-
- DummyControl( DummyControlImpl& implementation );
- DummyControl( Dali::Internal::CustomActor* internal );
+ DummyControl(DummyControlImpl& implementation);
+ DummyControl(Dali::Internal::CustomActor* internal);
};
/**
class DummyControlImpl : public Toolkit::Internal::Control
{
public:
-
static DummyControl New();
public:
- inline void EnableGestureDetection(GestureType::Value type) { Internal::Control::EnableGestureDetection(type); }
- inline void DisableGestureDetection(GestureType::Value type) { Internal::Control::DisableGestureDetection(type); }
- inline PinchGestureDetector GetPinchGestureDetector() const { return Internal::Control::GetPinchGestureDetector(); }
- inline PanGestureDetector GetPanGestureDetector() const { return Internal::Control::GetPanGestureDetector(); }
- inline TapGestureDetector GetTapGestureDetector() const { return Internal::Control::GetTapGestureDetector(); }
- inline LongPressGestureDetector GetLongPressGestureDetector() const { return Internal::Control::GetLongPressGestureDetector(); }
-
- void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual);
- void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled );
- void UnregisterVisual( Property::Index index );
- void EnableVisual( Property::Index index, bool enabled );
- bool IsVisualEnabled( Property::Index index );
- int GetVisualCount();
- Toolkit::Visual::Base GetVisual( Property::Index index );
- Animation CreateTransition( const Toolkit::TransitionData& transition );
- void DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes );
-
- static void SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value );
-
- static Property::Value GetProperty( BaseObject* object, Dali::Property::Index propertyIndex );
+ inline void EnableGestureDetection(GestureType::Value type)
+ {
+ Internal::Control::EnableGestureDetection(type);
+ }
+ inline void DisableGestureDetection(GestureType::Value type)
+ {
+ Internal::Control::DisableGestureDetection(type);
+ }
+ inline PinchGestureDetector GetPinchGestureDetector() const
+ {
+ return Internal::Control::GetPinchGestureDetector();
+ }
+ inline PanGestureDetector GetPanGestureDetector() const
+ {
+ return Internal::Control::GetPanGestureDetector();
+ }
+ inline TapGestureDetector GetTapGestureDetector() const
+ {
+ return Internal::Control::GetTapGestureDetector();
+ }
+ inline LongPressGestureDetector GetLongPressGestureDetector() const
+ {
+ return Internal::Control::GetLongPressGestureDetector();
+ }
+
+ void RegisterVisual(Property::Index index, Toolkit::Visual::Base visual);
+ void RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, bool enabled);
+ void RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, int depthIndex);
+ void UnregisterVisual(Property::Index index);
+ void EnableVisual(Property::Index index, bool enabled);
+ bool IsVisualEnabled(Property::Index index);
+ int GetVisualCount();
+ Toolkit::Visual::Base GetVisual(Property::Index index);
+ Animation CreateTransition(const Toolkit::TransitionData& transition);
+ void DoAction(Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes);
+
+ static void SetProperty(BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value);
+
+ static Property::Value GetProperty(BaseObject* object, Dali::Property::Index propertyIndex);
// Used to test signal connections
- void CustomSlot1( Actor actor );
+ void CustomSlot1(Actor actor);
- bool mCustomSlot1Called;
+ bool mCustomSlot1Called;
typedef std::vector<Property::Index> VisualIndices;
- VisualIndices mRegisteredVisualIndices;
+ VisualIndices mRegisteredVisualIndices;
protected:
-
DummyControlImpl();
~DummyControlImpl() override;
namespace Impl
{
-
/**
* Cannot create an instance of Internal::Control, so use this dummy class for the implementation.
* This class DOES override Internal::Control's behaviour.
class DummyControl : public Toolkit::DummyControlImpl
{
public:
-
- typedef std::function<void( Size )> RelayoutCallbackFunc;
+ typedef std::function<void(Size)> RelayoutCallbackFunc;
static Toolkit::DummyControl New();
- void SetLayout( Property::Index visualIndex, Property::Map& map );
+ void SetLayout(Property::Index visualIndex, Property::Map& map);
- void SetRelayoutCallback( RelayoutCallbackFunc callback );
+ void SetRelayoutCallback(RelayoutCallbackFunc callback);
private:
-
DummyControl();
~DummyControl() override;
private: // From Internal::Control
-
void OnInitialize() override;
bool OnAccessibilityActivated() override;
- bool OnAccessibilityValueChange( bool isIncrease ) override;
+ bool OnAccessibilityValueChange(bool isIncrease) override;
- void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) override;
- void OnPinch(const PinchGesture& pinch) override;
- void OnPan(const PanGesture& pan) override;
- void OnTap(const TapGesture& tap) override;
- void OnLongPress(const LongPressGesture& longPress) override;
+ void OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change) override;
+ void OnPinch(const PinchGesture& pinch) override;
+ void OnPan(const PanGesture& pan) override;
+ void OnTap(const TapGesture& tap) override;
+ void OnLongPress(const LongPressGesture& longPress) override;
Vector3 GetNaturalSize() override;
- bool OnKeyEvent(const KeyEvent& event) override;
+ bool OnKeyEvent(const KeyEvent& event) override;
private: // From CustomActorImpl
-
- void OnSceneConnection( int depth ) override;
+ void OnSceneConnection(int depth) override;
void OnSceneDisconnection() override;
void OnChildAdd(Actor& child) override;
void OnChildRemove(Actor& child) override;
void OnSizeAnimation(Animation& animation, const Vector3& targetSize) override;
void OnKeyInputFocusGained() override;
void OnKeyInputFocusLost() override;
- void OnRelayout( const Vector2& size, RelayoutContainer& container ) override;
+ void OnRelayout(const Vector2& size, RelayoutContainer& container) override;
- DALI_INTERNAL DummyControl( const DummyControl& );
- DALI_INTERNAL DummyControl& operator=( const DummyControl& );
+ DALI_INTERNAL DummyControl(const DummyControl&);
+ DALI_INTERNAL DummyControl& operator=(const DummyControl&);
public:
-
- bool initializeCalled;
- bool activatedCalled;
- bool onAccValueChangeCalled;
- bool themeChangeCalled;
- bool fontChangeCalled;
- bool pinchCalled;
- bool panCalled;
- bool tapCalled;
- bool longPressCalled;
- bool stageConnectionCalled;
- bool stageDisconnectionCalled;
- bool childAddCalled;
- bool childRemoveCalled;
- bool sizeSetCalled;
- bool sizeAnimationCalled;
- bool hoverEventCalled;
- bool wheelEventCalled;
- bool keyEventCalled;
- bool keyInputFocusGained;
- bool keyInputFocusLost;
+ bool initializeCalled;
+ bool activatedCalled;
+ bool onAccValueChangeCalled;
+ bool themeChangeCalled;
+ bool fontChangeCalled;
+ bool pinchCalled;
+ bool panCalled;
+ bool tapCalled;
+ bool longPressCalled;
+ bool stageConnectionCalled;
+ bool stageDisconnectionCalled;
+ bool childAddCalled;
+ bool childRemoveCalled;
+ bool sizeSetCalled;
+ bool sizeAnimationCalled;
+ bool hoverEventCalled;
+ bool wheelEventCalled;
+ bool keyEventCalled;
+ bool keyInputFocusGained;
+ bool keyInputFocusLost;
static int constructorCount;
static int destructorCount;
- Property::Map mLayouts;
+ Property::Map mLayouts;
RelayoutCallbackFunc mRelayoutCallback;
-
};
} // namespace Impl
void RemoveIdle(CallbackBase* callback);
void RunIdles();
+ void RequestUpdateOnce();
+
static Integration::Scene GetScene(Dali::Window window);
Dali::RenderSurfaceInterface& GetSurface();
mReturnCallbacks.Swap(reusedCallbacks);
}
+void Adaptor::RequestUpdateOnce()
+{
+ if(mTestApplication)
+ {
+ auto scene = mTestApplication->GetScene();
+ if(scene)
+ {
+ tet_printf("Adaptor::RequestUpdateOnce()\n");
+ scene.KeepRendering(0.0f);
+ }
+ }
+}
+
Dali::RenderSurfaceInterface& Adaptor::GetSurface()
{
DALI_ASSERT_ALWAYS(!mWindows.empty());
Dali::Clipboard::DataReceivedSignalType& DataReceivedSignal();
/**
+ * @copydoc Dali::Clipboard::HasType()
+ */
+ bool HasType(const std::string& mimeType);
+
+ /**
* @copydoc Dali::Clipboard::SetData()
*/
bool SetData(const Dali::Clipboard::ClipData& clipData);
return mDataReceivedSignal;
}
+bool Clipboard::HasType(const std::string& mimeType)
+{
+ return mMimeType == mimeType ? true : false;
+}
+
bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
{
mMimeType = clipData.GetMimeType();
DataReceivedSignalType& DataReceivedSignal();
/**
+ * @brief Check if there is data in the clipboard with a given mime type.
+ * @param[in] mimeType mime type to search for.
+ * @return bool true if there is data, otherwise false.
+ */
+ bool HasType(const std::string& mimeType);
+
+ /**
* @brief Send the given data to the clipboard.
* @param[in] clipData data to send to the clipboard
* @return bool true if the internal clipboard sending was successful.
value = resultMap.Find(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, "totalFrameNumber");
DALI_TEST_CHECK(value);
- DALI_TEST_EQUALS(value->Get<int>(), 4, TEST_LOCATION);
+ DALI_TEST_EQUALS(value->Get<int>(), -1, TEST_LOCATION);
value = resultMap.Find(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth");
DALI_TEST_CHECK(value);
END_TEST;
}
-
int UtcDaliAnimatedImageVisualControlVisibilityChanged(void)
{
ToolkitTestApplication application;
DALI_TEST_EQUALS(value->Get<int>(), 0, TEST_LOCATION);
END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliAnimatedImageVisualFrameCountBeforeLoadingFinished(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliAnimatedImageVisualFrameCountBeforeLoadingFinished");
+
+ Property::Map propertyMap;
+ propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_IMAGE)
+ .Add(ImageVisual::Property::URL, TEST_GIF_FILE_NAME)
+ .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ Property::Map resultMap1;
+ visual.CreatePropertyMap(resultMap1);
+ Property::Value* value1 = resultMap1.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+ DALI_TEST_CHECK(value1);
+ DALI_TEST_EQUALS(value1->Get<int>(), -1, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ DummyControl actor = DummyControl::New(true);
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+ Property::Map resultMap2;
+ visual.CreatePropertyMap(resultMap2);
+ Property::Value* value2 = resultMap2.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+ DALI_TEST_CHECK(value2);
+ DALI_TEST_EQUALS(value2->Get<int>(), -1, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ Vector2 controlSize(20.f, 30.f);
+ actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 2 - load & render a frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ Property::Map resultMap3;
+ visual.CreatePropertyMap(resultMap3);
+ Property::Value* value3 = resultMap3.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+ DALI_TEST_CHECK(value3);
+ DALI_TEST_EQUALS(value3->Get<int>(), 4, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ END_TEST;
+}
}
}
+/**
+ * @brief Retry function to get playrange until expect values comes.
+ * @note This function might consume EventThreadTrigger.
+ *
+ * @param[in] dummyControl The control for test.
+ * @param[in] expectStartFrame Expect start frame.
+ * @param[in] expectEndFrame Expect end frame.
+ * @param[in] retrialFrames Retry required frame value list.
+ * @param[in] testLocation Location info of UTC. It will be used when UTC failed.
+ */
+void CheckAndRetryPlayRange(DummyControl dummyControl, int expectStartFrame, int expectEndFrame, std::vector<std::pair<int, int>> retrialFrames, const char* testLocation)
+{
+ int tryCount = 0;
+ int tryCountMax = 25;
+ while(++tryCount <= tryCountMax)
+ {
+ Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+ Property::Value* value = resultMap.Find(DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY);
+ DALI_TEST_CHECK(value);
+
+ Property::Array* result = value->GetArray();
+ DALI_TEST_CHECK(result);
+ DALI_TEST_EQUALS(result->Count(), 2, TEST_LOCATION);
+
+ bool tryAgain = false;
+ for(auto& framePair : retrialFrames)
+ {
+ if(result->GetElementAt(0).Get<int>() == framePair.first && result->GetElementAt(1).Get<int>() == framePair.second)
+ {
+ tryAgain = true;
+ break;
+ }
+ }
+ if(tryAgain)
+ {
+ tet_printf("Retry to get value again! [%d]\n", tryCount);
+ // Dummy sleep 1 second.
+ Test::WaitForEventThreadTrigger(1, 1);
+ continue;
+ }
+
+ DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), expectStartFrame, testLocation);
+ DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), expectEndFrame, testLocation);
+ break;
+ }
+ DALI_TEST_CHECK(tryCount <= tryCountMax);
+}
+
+/**
+ * @brief Retry function to get current frame until expect values comes.
+ * @note This function might consume EventThreadTrigger.
+ *
+ * @param[in] dummyControl The control for test.
+ * @param[in] expectCurrentFrame Expect current frame.
+ * @param[in] retrialFrames Retry required frame value list.
+ * @param[in] testLocation Location info of UTC. It will be used when UTC failed.
+ */
+void CheckAndRetryCurrentFrame(DummyControl dummyControl, int expectCurrentFrame, std::vector<int> retrialFrames, const char* testLocation)
+{
+ int tryCount = 0;
+ int tryCountMax = 25;
+ while(++tryCount <= tryCountMax)
+ {
+ Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+ Property::Value* value = resultMap.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER, Property::INTEGER);
+ DALI_TEST_CHECK(value);
+
+ int32_t result = value->Get<int32_t>();
+
+ bool tryAgain = false;
+ for(auto& frame : retrialFrames)
+ {
+ if(result == frame)
+ {
+ tryAgain = true;
+ break;
+ }
+ }
+ if(tryAgain)
+ {
+ tet_printf("Retry to get value again! [%d]\n", tryCount);
+ // Dummy sleep 1 second.
+ Test::WaitForEventThreadTrigger(1, 1);
+ continue;
+ }
+
+ DALI_TEST_EQUALS(result, expectCurrentFrame, testLocation);
+ break;
+ }
+ DALI_TEST_CHECK(tryCount <= tryCountMax);
+}
+
} // namespace
int UtcDaliVisualFactoryGetAnimatedVectorImageVisual01(void)
// Trigger count is 2 - load & render a frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+ // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+ // Consume it if required.
+ if(actor.GetRendererCount() == 0)
+ {
+ tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+ Test::WaitForEventThreadTrigger(1, 1);
+ }
+
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
.Add("stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME)
.Add("loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE)
.Add("redrawInScalingDown", false)
+ .Add("enableFrameCache", false)
+ .Add("notifyAfterRasterization", false)
.Add("cornerRadius", cornerRadius)
.Add("borderlineWidth", borderlineWidth)
.Add("borderlineColor", borderlineColor)
.Add("borderlineOffset", borderlineOffset)
.Add("desiredWidth", desiredWidth)
- .Add("desiredHeight", desiredHeight)
- .Add("useFixedCache", false);
+ .Add("desiredHeight", desiredHeight);
Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
DALI_TEST_CHECK(visual);
// Trigger count is 1 - render a frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+ // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+ // Consume it if required.
+ if(actor.GetRendererCount() == 0)
+ {
+ tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+ Test::WaitForEventThreadTrigger(1, 1);
+ }
+
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
DALI_TEST_CHECK(value);
DALI_TEST_CHECK(value->Get<bool>() == false);
+ value = resultMap.Find(DevelImageVisual::Property::ENABLE_FRAME_CACHE, Property::BOOLEAN);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<bool>() == false);
+
+ value = resultMap.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, Property::BOOLEAN);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<bool>() == false);
+
value = resultMap.Find(DevelVisual::Property::CORNER_RADIUS, Property::VECTOR4);
DALI_TEST_CHECK(value);
DALI_TEST_EQUALS(value->Get<Vector4>(), Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius), TEST_LOCATION);
DALI_TEST_CHECK(value);
DALI_TEST_CHECK(value->Get<bool>() == false); // Check default value
+ value = resultMap.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, Property::BOOLEAN);
+ DALI_TEST_CHECK(value);
+ DALI_TEST_CHECK(value->Get<bool>() == false); // Check default value
+
value = resultMap.Find(DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN, Property::BOOLEAN);
DALI_TEST_CHECK(value);
DALI_TEST_CHECK(value->Get<bool>() == true); // Check default value
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
// Trigger count is 2 - load & render a frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+ // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+ // Consume it if required.
+ if(actor.GetRendererCount() == 0)
+ {
+ tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+ Test::WaitForEventThreadTrigger(1, 1);
+ }
+
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
// Set invalid play range
array.Clear();
array.PushBack(1);
- array.PushBack(100);
+ array.PushBack(totalFrameNumber + 100);
attributes.Clear();
attributes.Add(DevelImageVisual::Property::PLAY_RANGE, array);
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
- value = map.Find(DevelImageVisual::Property::PLAY_RANGE);
-
- result = value->GetArray();
- result->GetElementAt(0).Get(resultStartFrame);
- result->GetElementAt(1).Get(resultEndFrame);
-
- DALI_TEST_EQUALS(resultStartFrame, 1, TEST_LOCATION);
- DALI_TEST_EQUALS(resultEndFrame, totalFrameNumber - 1, TEST_LOCATION); // Should be clamped
+ // Should be clamped.
+ CheckAndRetryPlayRange(actor, 1, totalFrameNumber - 1, {{startFrame, endFrame}}, TEST_LOCATION);
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, Property::Map());
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
- // To make event trigger
- actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
-
application.SendNotification();
application.Render();
+ // Jump to action when paused, will make one or more event trigger
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
- value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
- DALI_TEST_EQUALS(value->Get<int>(), 3, TEST_LOCATION);
+ // Test whether current frame is 3.
+ CheckAndRetryCurrentFrame(actor, 3, {0, 1}, TEST_LOCATION);
array.Clear();
array.PushBack(0);
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes);
// To make event trigger
- actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
application.SendNotification();
application.Render();
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
- value = map.Find(DevelImageVisual::Property::PLAY_RANGE);
-
- result = value->GetArray();
- result->GetElementAt(0).Get(resultStartFrame);
- result->GetElementAt(1).Get(resultEndFrame);
-
- DALI_TEST_EQUALS(0, resultStartFrame, TEST_LOCATION);
- DALI_TEST_EQUALS(2, resultEndFrame, TEST_LOCATION);
+ CheckAndRetryPlayRange(actor, 0, 2, {{1, totalFrameNumber - 1}}, TEST_LOCATION);
+ map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
DALI_TEST_EQUALS(value->Get<int>(), 2, TEST_LOCATION); // CURRENT_FRAME_NUMBER should be changed also.
// Trigger count is 2 - load & render a frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+ // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+ // Consume it if required.
+ if(actor.GetRendererCount() == 0)
+ {
+ tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+ Test::WaitForEventThreadTrigger(1, 1);
+ }
+
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
// renderer is added to actor
- DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
Renderer renderer = actor.GetRendererAt(0u);
DALI_TEST_CHECK(renderer);
END_TEST;
}
-int UtcDaliAnimatedVectorImageVisualUsedFixedCache(void)
+int UtcDaliAnimatedVectorImageVisualEnableFrameCache(void)
{
ToolkitTestApplication application;
- tet_infoline("UtcDaliAnimatedVectorImageVisualUsedFixedCache");
+ tet_infoline("UtcDaliAnimatedVectorImageVisualEnableFrameCache");
Property::Map propertyMap;
propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
DummyControl actor = DummyControl::New(true);
DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
- //actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
application.GetScene().Add(actor);
application.SendNotification();
application.Render();
- // Trigger count is 1 - render a frame
+ // Trigger count is 1 - load
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
Vector2 controlSize(200.f, 200.f);
application.SendNotification();
application.Render();
- // Trigger count is 1 - load
+ // Trigger count is 1 - render a frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
// renderer is added to actor
END_TEST;
}
-int UtcDaliAnimatedVectorImageVisualUsedFixedCacheFailed(void)
+int UtcDaliAnimatedVectorImageVisualEnableFrameCacheFailed(void)
{
ToolkitTestApplication application;
- tet_infoline("UtcDaliAnimatedVectorImageVisualUsedFixedCacheFailed");
+ tet_infoline("UtcDaliAnimatedVectorImageVisualEnableFrameCacheFailed");
Property::Map propertyMap;
propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
END_TEST;
}
+int UtcDaliAnimatedVectorImageVisualNotifyAfterRasterization(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliAnimatedVectorImageVisualNotifyAfterRasterization");
+
+ Property::Map propertyMap;
+ propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+ .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
+ .Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, true)
+ .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ DummyControl actor = DummyControl::New(true);
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 1 - load
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ Vector2 controlSize(200.f, 200.f);
+ actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 1 - render a frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ // Play animation
+ Property::Map attributes;
+ DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+ application.SendNotification();
+ application.Render();
+
+ // There might be 1 event triggered if render frame spend long time.
+ // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+ // Consume it if required.
+ if(actor.GetRendererCount() == 0)
+ {
+ tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+ Test::WaitForEventThreadTrigger(1, 1);
+ }
+
+ // renderer is added to actor
+ DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+ Renderer renderer = actor.GetRendererAt(0u);
+ DALI_TEST_CHECK(renderer);
+
+ // Check renderer behavior
+ DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::IF_REQUIRED);
+
+ Property::Map map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+ Property::Value* value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+ DALI_TEST_CHECK(value->Get<bool>() == true);
+
+ propertyMap.Clear();
+ propertyMap.Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, false);
+ DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
+ application.SendNotification();
+ application.Render();
+
+ // Check renderer behavior again
+ DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::CONTINUOUSLY);
+
+ map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+ value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+ DALI_TEST_CHECK(value->Get<bool>() == false);
+
+ propertyMap.Clear();
+ propertyMap.Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, true);
+ DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
+ application.SendNotification();
+ application.Render();
+
+ // Check renderer behavior again
+ DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::IF_REQUIRED);
+
+ map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+ value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+ DALI_TEST_CHECK(value->Get<bool>() == true);
+
+ END_TEST;
+}
+
int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
{
ToolkitTestApplication application;
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 2);
- // To make event trigger
- actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
-
application.SendNotification();
application.Render();
+ // Trigger count is 1 - Jump to during stopped
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
Property::Map map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
// To make event trigger
- actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
application.SendNotification();
application.Render();
// Wait for animation finish
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ // Note : AnimationFinished will occure force-render, and it might required another trigger. Test one more trigger now.
+ Test::WaitForEventThreadTrigger(1, 1);
// Jump to 3
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
- // To make event trigger
- actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
-
application.SendNotification();
application.Render();
+ // Trigger count is 1 - Jump to during stopped.
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
Property::Array* result = value->GetArray();
DALI_TEST_CHECK(result);
- DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == startFrame);
- DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == endFrame);
+ DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), startFrame, TEST_LOCATION);
+ DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), endFrame, TEST_LOCATION);
playRange.Clear();
playRange.PushBack(0);
result = value->GetArray();
DALI_TEST_CHECK(result);
- DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == 0);
- DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == 2);
+ // Ensure that vector data sended well.
+ CheckAndRetryPlayRange(actor, 0, 2, {{startFrame, endFrame}}, TEST_LOCATION);
attributes.Clear();
result = value->GetArray();
DALI_TEST_CHECK(result);
- DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == startFrame);
- DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == endFrame);
+ // Ensure that vector data sended well.
+ CheckAndRetryPlayRange(actor, startFrame, endFrame, {{0, 2}}, TEST_LOCATION);
// Play and update property
attributes.Clear();
application.GetScene().Add(dummyControl);
- // Retry function to get playrange until expect values comes.
- auto CheckAndRetryPlayRange = [&](int expectStartFrame, int expectEndFrame, std::vector<std::pair<int, int>> retrialFrames) {
- int tryCount = 0;
- int tryCountMax = 30;
- while(++tryCount <= tryCountMax)
- {
- Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-
- Property::Value* value = resultMap.Find(DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY);
- DALI_TEST_CHECK(value);
-
- Property::Array* result = value->GetArray();
- DALI_TEST_CHECK(result);
- DALI_TEST_EQUALS(result->Count(), 2, TEST_LOCATION);
-
- bool tryAgain = false;
- for(auto& framePair : retrialFrames)
- {
- if(result->GetElementAt(0).Get<int>() == framePair.first && result->GetElementAt(1).Get<int>() == framePair.second)
- {
- tryAgain = true;
- break;
- }
- }
- if(tryAgain)
- {
- tet_printf("Retry to get value again! [%d]\n", tryCount);
- // Dummy sleep 1 second.
- Test::WaitForEventThreadTrigger(1, 1);
- continue;
- }
-
- DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), expectStartFrame, TEST_LOCATION);
- DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), expectEndFrame, TEST_LOCATION);
- break;
- }
- DALI_TEST_CHECK(tryCount <= tryCountMax);
- };
-
tet_printf("Pause lottie first.\n");
Property::Map attributes;
} while(totalFrameCount == 0);
// Ensure that vector data sended well.
- CheckAndRetryPlayRange(startFrame, endFrame, {{0, 0}, {0, totalFrameCount - 1}});
+ CheckAndRetryPlayRange(dummyControl, startFrame, endFrame, {{0, 0}, {0, totalFrameCount - 1}}, TEST_LOCATION);
resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
application.Render(16);
// Ensure that vector data sended well.
- CheckAndRetryPlayRange(changedStartFrame2, changedEndFrame2, {{changedStartFrame1, changedEndFrame1}, {startFrame, endFrame}});
+ CheckAndRetryPlayRange(dummyControl, changedStartFrame2, changedEndFrame2, {{changedStartFrame1, changedEndFrame1}, {startFrame, endFrame}}, TEST_LOCATION);
resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
END_TEST;
}
+int UtcDaliImageViewTransitionEffect05(void)
+{
+ tet_printf("Testing user's transition effect in ImageView \n");
+ ToolkitTestApplication application;
+
+ Property::Map map;
+ map["target"] = "image";
+ map["property"] = "opacity";
+ map["initialValue"] = 0.2f;
+ map["targetValue"] = 1.0f;
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "EASE_IN_OUT")
+ .Add("timePeriod", Property::Map().Add("delay", 0.0f).Add("duration", 2.0f))
+ .Add("animationType", "BETWEEN");
+
+ ImageView imageView = ImageView::New();
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 200.0f));
+ imageView.SetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT, true);
+ imageView.SetProperty(ImageView::Property::TRANSITION_EFFECT_OPTION, map);
+ imageView.SetImage(gImage_600_RGB);
+ application.GetScene().Add(imageView);
+
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ Property::Value value;
+ value = imageView.GetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT);
+ bool transition;
+ DALI_TEST_CHECK(value.Get(transition));
+ DALI_TEST_CHECK(transition == true);
+
+ // Clear all cached
+ imageView.Unparent();
+ imageView.Reset();
+
+ END_TEST;
+}
+
+int UtcDaliImageViewTransitionEffect06(void)
+{
+ tet_printf("Testing user's transition effect in ImageView \n");
+ ToolkitTestApplication application;
+
+ Property::Map map;
+ map["target"] = "image";
+ map["property"] = "opacity";
+ map["initialValue"] = 0.2f;
+ map["targetValue"] = 1.0f;
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "EASE_IN_OUT")
+ .Add("timePeriod", Property::Map().Add("delay", 0.0f).Add("duration", 2.0f))
+ .Add("animationType", "TO");
+
+ ImageView imageView = ImageView::New();
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 200.0f));
+ imageView.SetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT, true);
+ imageView.SetProperty(ImageView::Property::TRANSITION_EFFECT_OPTION, map);
+ imageView.SetImage(gImage_600_RGB);
+ application.GetScene().Add(imageView);
+
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ Property::Value value;
+ value = imageView.GetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT);
+ bool transition;
+ DALI_TEST_CHECK(value.Get(transition));
+ DALI_TEST_CHECK(transition == true);
+
+ // Clear all cached
+ imageView.Unparent();
+ imageView.Reset();
+
+ END_TEST;
+}
+
+
+
int UtcDaliImageViewImageLoadFailureAndReload01(void)
{
tet_infoline("Try to load invalid image first, and then reload after that image valid.");
END_TEST;
}
+
+int UtcDaliImageVisualCustomWrapModePixelArea02(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Request image visual with a Property::Map, test custom wrap mode and pixel area");
+
+ static std::vector<UniformData> customUniforms =
+ {
+ UniformData("pixelArea", Property::Type::VECTOR4),
+ UniformData("wrapMode", Property::Type::VECTOR2),
+ };
+
+ TestGraphicsController& graphics = application.GetGraphicsController();
+ graphics.AddCustomUniforms(customUniforms);
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+ const int width = 34;
+ const int height = 34;
+ const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_SMALL_IMAGE_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::DESIRED_WIDTH, width);
+ propertyMap.Insert(ImageVisual::Property::DESIRED_HEIGHT, height);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+ propertyMap.Insert(ImageVisual::Property::PIXEL_AREA, pixelArea);
+ propertyMap.Insert(ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT);
+ propertyMap.Insert(ImageVisual::Property::WRAP_MODE_V, WrapMode::CLAMP_TO_EDGE);
+
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+ texParameterTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(2000, 2000));
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ application.GetScene().Add(actor);
+
+ // loading started
+ application.SendNotification();
+ application.Render();
+
+ // Wait image load complete.
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ // Following gl function should not be called
+ std::stringstream out;
+ out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+ DALI_TEST_CHECK(texParameterTrace.FindMethodAndParams("TexParameteri", out.str()));
+ out.str("");
+ out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_CLAMP_TO_EDGE;
+ DALI_TEST_CHECK(texParameterTrace.FindMethodAndParams("TexParameteri", out.str()));
+
+ // test the uniforms which used to handle the wrap mode
+ Renderer renderer = actor.GetRendererAt(0u);
+ DALI_TEST_CHECK(renderer);
+
+ Property::Value pixelAreaValue = renderer.GetProperty(renderer.GetPropertyIndex("pixelArea"));
+ DALI_TEST_EQUALS(pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION);
+ Vector4 pixelAreaUniform;
+ DALI_TEST_CHECK(gl.GetUniformValue<Vector4>("pixelArea", pixelAreaUniform));
+ DALI_TEST_EQUALS(pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ actor.Unparent();
+ DALI_TEST_CHECK(actor.GetRendererCount() == 0u);
+
+ END_TEST;
+}
+
int UtcDaliImageVisualCustomWrapModeNoAtlas(void)
{
ToolkitTestApplication application;
const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS = "inputMethodSettings";
const char* const PROPERTY_NAME_INPUT_FILTER = "inputFilter";
+const char* const PROPERTY_NAME_REMOVE_FRONT_INSET = "removeFrontInset";
+const char* const PROPERTY_NAME_REMOVE_BACK_INSET = "removeBackInset";
+
const Vector4 PLACEHOLDER_TEXT_COLOR(0.8f, 0.8f, 0.8f, 0.8f);
const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f); // The text highlight color.
DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextEditor::Property::STRIKETHROUGH);
DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_INPUT_STRIKETHROUGH) == DevelTextEditor::Property::INPUT_STRIKETHROUGH);
DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_SELECTION_POPUP_STYLE) == DevelTextEditor::Property::SELECTION_POPUP_STYLE);
+ DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextEditor::Property::REMOVE_FRONT_INSET);
+ DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextEditor::Property::REMOVE_BACK_INSET);
END_TEST;
}
outlineMapSet["color"] = Color::RED;
outlineMapSet["width"] = 2.0f;
+ outlineMapSet["offset"] = Vector2(0.0f, 0.0f);
+ outlineMapSet["blurRadius"] = 0.0f;
editor.SetProperty(TextEditor::Property::OUTLINE, outlineMapSet);
editor.SetProperty(DevelTextEditor::Property::MIN_LINE_SIZE, 50.f);
DALI_TEST_EQUALS(editor.GetProperty<float>(DevelTextEditor::Property::MIN_LINE_SIZE), 50.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+ // Check Remove Front/Back Inset Property
+ DALI_TEST_CHECK(editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_FRONT_INSET));
+ editor.SetProperty(DevelTextEditor::Property::REMOVE_FRONT_INSET, false);
+ DALI_TEST_CHECK(!editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_FRONT_INSET));
+
+ DALI_TEST_CHECK(editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_BACK_INSET));
+ editor.SetProperty(DevelTextEditor::Property::REMOVE_BACK_INSET, false);
+ DALI_TEST_CHECK(!editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_BACK_INSET));
+
+ application.SendNotification();
+ application.Render();
+
END_TEST;
}
TestTextGeometryUtils::CheckRectGeometryResult(textBoundingRectangle, expectedTextBoundingRectangle);
END_TEST;
-}
\ No newline at end of file
+}
+
+int utcDaliTextEditorRemoveFrontInset(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextEditorRemoveFrontInset");
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK(editor);
+ application.GetScene().Add(editor);
+ application.SendNotification();
+ application.Render();
+ DevelTextEditor::SetRemoveFrontInset(editor, false);
+ DALI_TEST_CHECK(!DevelTextEditor::IsRemoveFrontInset(editor));
+ END_TEST;
+}
+int utcDaliTextEditorRemoveBackInset(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextEditorRemoveBackInset");
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK(editor);
+ application.GetScene().Add(editor);
+ application.SendNotification();
+ application.Render();
+ DevelTextEditor::SetRemoveBackInset(editor, false);
+ DALI_TEST_CHECK(!DevelTextEditor::IsRemoveBackInset(editor));
+ END_TEST;
+}
const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR = "grabHandleColor";
const char* const PROPERTY_NAME_INPUT_FILTER = "inputFilter";
+const char* const PROPERTY_NAME_REMOVE_FRONT_INSET = "removeFrontInset";
+const char* const PROPERTY_NAME_REMOVE_BACK_INSET = "removeBackInset";
+
const Vector4 PLACEHOLDER_TEXT_COLOR(0.8f, 0.8f, 0.8f, 0.8f);
const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f); // The text highlight color.
DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextField::Property::STRIKETHROUGH);
DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_INPUT_STRIKETHROUGH) == DevelTextField::Property::INPUT_STRIKETHROUGH);
DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_SELECTION_POPUP_STYLE) == DevelTextField::Property::SELECTION_POPUP_STYLE);
+ DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextField::Property::REMOVE_FRONT_INSET);
+ DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextField::Property::REMOVE_BACK_INSET);
END_TEST;
}
outlineMapSet["color"] = Color::RED;
outlineMapSet["width"] = 2.0f;
+ outlineMapSet["offset"] = Vector2(0.0f, 0.0f);
+ outlineMapSet["blurRadius"] = 0.0f;
field.SetProperty(TextField::Property::OUTLINE, outlineMapSet);
application.SendNotification();
application.Render();
+ // Check Remove Front/Back Inset Property
+ DALI_TEST_CHECK(field.GetProperty<bool>(DevelTextField::Property::REMOVE_FRONT_INSET));
+ field.SetProperty(DevelTextField::Property::REMOVE_FRONT_INSET, false);
+ DALI_TEST_CHECK(!field.GetProperty<bool>(DevelTextField::Property::REMOVE_FRONT_INSET));
+
+ DALI_TEST_CHECK(field.GetProperty<bool>(DevelTextField::Property::REMOVE_BACK_INSET));
+ field.SetProperty(DevelTextField::Property::REMOVE_BACK_INSET, false);
+ DALI_TEST_CHECK(!field.GetProperty<bool>(DevelTextField::Property::REMOVE_BACK_INSET));
+
+ application.SendNotification();
+ application.Render();
+
+
END_TEST;
}
event.AddPoint(GetPointUpInside(position));
application.ProcessEvent(event);
}
- DALI_TEST_EQUALS(field.GetProperty<std::string>(TextEditor::Property::TEXT), std::string("testTextFieldEvent"), TEST_LOCATION);
+ DALI_TEST_EQUALS(field.GetProperty<std::string>(TextField::Property::TEXT), std::string("testTextFieldEvent"), TEST_LOCATION);
+
+ Dali::Clipboard::ClipData htmlData("application/xhtml+xml", "testTextFieldEventHtml");
+ clipboard.SetData(htmlData);
+
+ field.SetProperty(TextField::Property::TEXT, "");
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Long Press
+ TestGenerateLongPress(application, 1.0f, 25.0f, 20);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ Wait(application, 500);
+
+ TestEndLongPress(application, 1.0f, 25.0f, 520);
+
+ // Long Press
+ TestGenerateLongPress(application, 1.0f, 25.0f, 600);
+
+ // Render and notify
+ application.Render();
+
+ Wait(application, 500);
+
+ stage = application.GetScene();
+ layer = stage.GetRootLayer();
+ actor = layer.FindChildByName("optionPaste");
+
+ if(actor)
+ {
+ Vector3 worldPosition = actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_POSITION);
+ Vector2 halfStageSize = stage.GetSize() / 2.0f;
+ Vector2 position(worldPosition.x + halfStageSize.width, worldPosition.y + halfStageSize.height);
+
+ Dali::Integration::TouchEvent event;
+ event = Dali::Integration::TouchEvent();
+ event.AddPoint(GetPointDownInside(position));
+ application.ProcessEvent(event);
+
+ event = Dali::Integration::TouchEvent();
+ event.AddPoint(GetPointUpInside(position));
+ application.ProcessEvent(event);
+ }
+ DALI_TEST_EQUALS(field.GetProperty<std::string>(TextField::Property::TEXT), std::string("testTextFieldEventHtml"), TEST_LOCATION);
END_TEST;
}
application.Render();
END_TEST;
-}
\ No newline at end of file
+}
+
+int utcDaliTextFieldRemoveFrontInset(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextFieldRemoveFrontInset");
+
+ TextField field = TextField::New();
+ DALI_TEST_CHECK(field);
+
+ application.GetScene().Add(field);
+ application.SendNotification();
+ application.Render();
+
+ DevelTextField::SetRemoveFrontInset(field, false);
+ DALI_TEST_CHECK(!DevelTextField::IsRemoveFrontInset(field));
+
+ END_TEST;
+}
+
+int utcDaliTextFieldRemoveBackInset(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextFieldRemoveBackInset");
+
+ TextField field = TextField::New();
+ DALI_TEST_CHECK(field);
+
+ application.GetScene().Add(field);
+ application.SendNotification();
+ application.Render();
+
+ DevelTextField::SetRemoveBackInset(field, false);
+ DALI_TEST_CHECK(!DevelTextField::IsRemoveBackInset(field));
+
+ END_TEST;
+}
const char* const PROPERTY_NAME_REMOVE_FRONT_INSET = "removeFrontInset";
const char* const PROPERTY_NAME_REMOVE_BACK_INSET = "removeBackInset";
+const char* const PROPERTY_NAME_REMOVE_CUTOUT = "cutout";
const std::string DEFAULT_FONT_DIR("/resources/fonts");
const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_CLICKED_COLOR) == DevelTextLabel::Property::ANCHOR_CLICKED_COLOR);
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextLabel::Property::REMOVE_FRONT_INSET);
DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextLabel::Property::REMOVE_BACK_INSET);
+ DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_CUTOUT) == DevelTextLabel::Property::CUTOUT);
END_TEST;
}
outlineMapSet["color"] = Color::RED;
outlineMapSet["width"] = 2.0f;
+ outlineMapSet["offset"] = Vector2(2.0f, 2.0f);
+ outlineMapSet["blurRadius"] = 3.0f;
label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
outlineMapGet = label.GetProperty<Property::Map>(TextLabel::Property::OUTLINE);
outlineMapSet.Clear();
outlineMapSet[Toolkit::DevelText::Outline::Property::COLOR] = Color::BLUE;
outlineMapSet[Toolkit::DevelText::Outline::Property::WIDTH] = 3.0f;
+ outlineMapSet[Toolkit::DevelText::Outline::Property::OFFSET] = Vector2(3.0f, 3.0f);
+ outlineMapSet[Toolkit::DevelText::Outline::Property::BLUR_RADIUS] = 4.0f;
+
label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
outlineMapGet = label.GetProperty<Property::Map>(TextLabel::Property::OUTLINE);
DALI_TEST_EQUALS(outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION);
- std::vector<std::string> outlineIndicesConversionTable = {"color", "width"};
+ std::vector<std::string> outlineIndicesConversionTable = {"color", "width", "offset", "blurRadius"};
DALI_TEST_EQUALS(DaliTestCheckMaps(outlineMapGet, outlineMapSet, outlineIndicesConversionTable), true, TEST_LOCATION);
// Check the background property
application.SendNotification();
application.Render();
+ // Check cutout Property
+ DALI_TEST_CHECK(!label.GetProperty<bool>(DevelTextLabel::Property::CUTOUT));
+ label.SetProperty(DevelTextLabel::Property::CUTOUT, true);
+ DALI_TEST_CHECK(label.GetProperty<bool>(DevelTextLabel::Property::CUTOUT));
+
+ application.SendNotification();
+ application.Render();
+
END_TEST;
}
DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION); // Rendering should be skipped
+ label.SetProperty(DevelTextLabel::Property::CUTOUT, true);
+
+ drawTrace.Reset();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION); // When cutout is enabled, should not be skipped
+
+ label.SetProperty(DevelTextLabel::Property::CUTOUT, false);
label.SetProperty(TextLabel::Property::TEXT_COLOR, Color::RED);
drawTrace.Reset();
outlineMapSet["color"] = Color::BLUE;
outlineMapSet["width"] = 2.0f;
+ outlineMapSet["offset"] = "2 2";
+ outlineMapSet["blurRadius"] = "3";
label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
application.SendNotification();
propertyMap.Insert("underline", underlineMapSet.Add("enable", true).Add("color", Color::GREEN).Add("height", 1).Add("type", Text::Underline::Type::SOLID).Add("dashWidth", 2).Add("dashGap", 1));
Property::Map outlineMapSet;
- propertyMap.Insert("outline", outlineMapSet.Add("color", Color::YELLOW).Add("width", 1));
+ propertyMap.Insert("outline", outlineMapSet.Add("color", Color::YELLOW).Add("width", 1).Add("offset", Vector2(2.0f, 2.0f)).Add("blurRadius", 3.0f));
Property::Map backgroundMapSet;
propertyMap.Insert("textBackground", backgroundMapSet.Add("enable", true).Add("color", Color::CYAN));
dummyImpl.RegisterVisual(DummyControl::Property::FOCUS_VISUAL, focusVisual);
DALI_TEST_CHECK(focusVisual.GetDepthIndex() > foregroundVisual.GetDepthIndex());
- tet_infoline("Set depth index on a new visual before registering, the depth index should not have been changed");
+ tet_infoline("Set depth index on a new visual before registering, the depth index should not have been changed, and be clampled");
Visual::Base labelVisual = factory.CreateVisual(propertyMap);
- labelVisual.SetDepthIndex(-2000);
+ labelVisual.SetDepthIndex(static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX) - 100);
dummyImpl.RegisterVisual(DummyControl::Property::LABEL_VISUAL, labelVisual);
- DALI_TEST_EQUALS(labelVisual.GetDepthIndex(), -2000, TEST_LOCATION);
+ DALI_TEST_EQUALS(labelVisual.GetDepthIndex(), static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX), TEST_LOCATION);
tet_infoline("Replace visual, the depth index should be the same as what was previously set");
const int testVisual2DepthIndex = testVisual2.GetDepthIndex();
dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, testVisual2Replacement);
DALI_TEST_EQUALS(testVisual2Replacement.GetDepthIndex(), testVisual2DepthIndex, TEST_LOCATION);
- tet_infoline("Replace visual and set a depth index on the replacement, the depth index of the replacement should be honoured");
+ tet_infoline("Replace visual and set a depth index on the replacement, the depth index of the replacement should be honoured, and be clampled");
Visual::Base anotherTestVisual2Replacement = factory.CreateVisual(propertyMap);
- anotherTestVisual2Replacement.SetDepthIndex(2000);
+ anotherTestVisual2Replacement.SetDepthIndex(static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX) + 100);
dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, anotherTestVisual2Replacement);
- DALI_TEST_EQUALS(anotherTestVisual2Replacement.GetDepthIndex(), 2000, TEST_LOCATION);
+ DALI_TEST_EQUALS(anotherTestVisual2Replacement.GetDepthIndex(), static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX), TEST_LOCATION);
dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
application.GetScene().Add(dummyControl);
dummyControl.SetProperty(Control::Property::BACKGROUND, propertyMap);
- const int TEST_VISUAL_1_DEPTH_INDEX = 0;
+ const int TEST_VISUAL_1_DEPTH_INDEX = static_cast<int>(Toolkit::DepthIndex::CONTENT);
tet_printf("Register visual, should have depth index of %d\n", TEST_VISUAL_1_DEPTH_INDEX);
Visual::Base testVisual1 = factory.CreateVisual(propertyMap);
dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, testVisual1);
tet_printf("Register another visual, should have a depth index greater than previous(%d)\n", TEST_VISUAL_1_DEPTH_INDEX);
Visual::Base testVisual2 = factory.CreateVisual(propertyMap);
dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, testVisual2);
- DALI_TEST_CHECK(testVisual2.GetDepthIndex() > testVisual1.GetDepthIndex());
+ DALI_TEST_GREATER(testVisual2.GetDepthIndex(), testVisual1.GetDepthIndex(), TEST_LOCATION);
+
+ const int TEST_VISUAL_2_DEPTH_INDEX = testVisual2.GetDepthIndex();
+
+ tet_printf("Register other visual, should have a depth index greater than previous(%d)\n", TEST_VISUAL_2_DEPTH_INDEX);
+ Visual::Base testVisual3 = factory.CreateVisual(propertyMap);
+ dummyImpl.RegisterVisual(DummyControl::Property::FOREGROUND_VISUAL, testVisual3, Toolkit::DepthIndex::AUTO_INDEX);
+ DALI_TEST_GREATER(testVisual3.GetDepthIndex(), testVisual2.GetDepthIndex(), TEST_LOCATION);
dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
application.GetScene().Add(dummyControl);
mSkybox(),
mSkyboxOrientation(Quaternion()),
mSkyboxIntensity(1.0f),
+ mLightObservers(),
mShaderManager(new Scene3D::Loader::ShaderManager())
{
}
{
item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
item->NotifyShadowMapTexture(mShadowTexture);
- mItems.push_back(item);
+ mLightObservers.PushBack(item);
}
}
{
if(item)
{
- for(uint32_t i = 0; i < mItems.size(); ++i)
+ auto iter = mLightObservers.Find(item);
+ if(iter != mLightObservers.End())
{
- if(mItems[i] == item)
- {
- mItems.erase(mItems.begin() + i);
- break;
- }
+ mLightObservers.Erase(iter);
}
}
}
void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
{
mIblScaleFactor = scaleFactor;
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
mShadowLight.Reset();
mShadowTexture.Reset();
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
void SceneView::OnSceneDisconnection()
{
- mItems.clear();
+ mLightObservers.Clear();
Window window = mWindow.GetHandle();
if(window)
void SceneView::NotifyImageBasedLightTextureChange()
{
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
#include <dali-toolkit/internal/visuals/image/image-visual.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/integration-api/ordered-set.h>
#include <dali/public-api/actors/camera-actor.h>
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/adaptor-framework/window.h>
/////////////////////////////////////////////////////////////
// FrameBuffer and Rendertask to render child objects as a 3D Scene
- Dali::WeakHandle<Dali::Window> mWindow;
- Integration::SceneHolder mSceneHolder;
- CameraActor mDefaultCamera;
- CameraActor mSelectedCamera;
- std::vector<CameraActor> mCameras;
- std::vector<Scene3D::Internal::LightObserver*> mItems;
- Dali::FrameBuffer mFrameBuffer;
- Dali::Texture mTexture;
- Dali::RenderTask mRenderTask;
- Layer mRootLayer;
- int32_t mWindowOrientation;
- Dali::Actor mSkybox;
- Quaternion mSkyboxOrientation;
- float mSkyboxIntensity{1.0f};
- uint8_t mFrameBufferMultiSamplingLevel{0u};
+ Dali::WeakHandle<Dali::Window> mWindow;
+ Integration::SceneHolder mSceneHolder;
+ CameraActor mDefaultCamera;
+ CameraActor mSelectedCamera;
+ std::vector<CameraActor> mCameras;
+ Dali::FrameBuffer mFrameBuffer;
+ Dali::Texture mTexture;
+ Dali::RenderTask mRenderTask;
+ Layer mRootLayer;
+ int32_t mWindowOrientation;
+ Dali::Actor mSkybox;
+ Quaternion mSkyboxOrientation;
+ float mSkyboxIntensity{1.0f};
+ uint8_t mFrameBufferMultiSamplingLevel{0u};
+
+ Dali::Integration::OrderedSet<Scene3D::Internal::LightObserver, false> mLightObservers; ///< The set of items to be notified when light properties change. (not owned)
bool mWindowSizeChanged{false};
uint32_t mWindowWidth{0};
+#define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT)
#define ADD_EXTRA_SKINNING_ATTRIBUTES
#define ADD_EXTRA_WEIGHTS
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
{
if(mUri.find(EMBEDDED_DATA_PREFIX.data()) == 0 && mUri.find(EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.data(), EMBEDDED_DATA_PREFIX.length()) == EMBEDDED_DATA_PREFIX.length())
{
- uint32_t position = mUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.length());
+ auto position = mUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.length());
if(position != std::string::npos)
{
position += EMBEDDED_DATA_BASE64_ENCODING_TYPE.length();
}
else if(textureDefinition.mImageUri.find(EMBEDDED_DATA_PREFIX.data()) == 0 && textureDefinition.mImageUri.find(EMBEDDED_DATA_IMAGE_MEDIA_TYPE.data(), EMBEDDED_DATA_PREFIX.length()) == EMBEDDED_DATA_PREFIX.length())
{
- uint32_t position = textureDefinition.mImageUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_IMAGE_MEDIA_TYPE.length());
+ auto position = textureDefinition.mImageUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_IMAGE_MEDIA_TYPE.length());
if(position != std::string::npos)
{
position += EMBEDDED_DATA_BASE64_ENCODING_TYPE.length();
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/public-api/object/property-map.h>
#include <dali/public-api/object/type-info.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/control.h>
#include <dali-toolkit/public-api/controls/image-view/image-view.h>
{
namespace
{
-static std::string GetLocaleText(std::string string, const char* domain = "dali-toolkit")
+constexpr const char* ATTR_IMG_SRC_KEY = "imgSrc";
+
+std::string GetLocaleText(std::string string, const char* domain = "dali-toolkit")
{
#ifdef DGETTEXT_ENABLED
/*TODO: currently non-localized string is used as a key for translation lookup. In case the lookup key formatting is forced
#endif
}
-static Dali::Actor CreateHighlightIndicatorActor()
+Dali::Actor CreateHighlightIndicatorActor()
{
std::string focusBorderImagePath(AssetManager::GetDaliImagePath());
focusBorderImagePath += "/keyboard_focus.9.png";
return actor;
}
+
+std::string FetchImageSrcFromMap(const Dali::Property::Map& imageMap)
+{
+ auto urlVal = imageMap.Find(Toolkit::ImageVisual::Property::URL);
+ if(urlVal)
+ {
+ if(urlVal->GetType() == Dali::Property::STRING)
+ {
+ return urlVal->Get<std::string>();
+ }
+ else if(urlVal->GetType() == Dali::Property::ARRAY)
+ {
+ auto urlArray = urlVal->GetArray();
+ if(urlArray && !urlArray->Empty())
+ {
+ // Returns first element if url is an array
+ return (*urlArray)[0].Get<std::string>();
+ }
+ }
+ }
+ return {};
+}
+
+std::string FetchImageSrc(const Toolkit::ImageView& imageView)
+{
+ const auto imageUrl = imageView.GetProperty<std::string>(Toolkit::ImageView::Property::IMAGE);
+ if(!imageUrl.empty())
+ {
+ return imageUrl;
+ }
+
+ const auto imageMap = imageView.GetProperty<Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE);
+ if(!imageMap.Empty())
+ {
+ return FetchImageSrcFromMap(imageMap);
+ }
+ return {};
+}
+
} // unnamed namespace
ControlAccessible::ControlAccessible(Dali::Actor self)
states[State::FOCUSABLE] = self.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE);
states[State::FOCUSED] = Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor() == self;
states[State::HIGHLIGHTABLE] = self.GetProperty<bool>(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE);
- states[State::HIGHLIGHTED] = GetCurrentlyHighlightedActor() == self;
+ states[State::HIGHLIGHTED] = IsHighlighted();
states[State::ENABLED] = true;
states[State::SENSITIVE] = (Dali::DevelActor::IsHittable(self) && Dali::DevelActor::GetTouchRequired(self));
states[State::VISIBLE] = self.GetProperty<bool>(Actor::Property::VISIBLE);
result.emplace(automationIdKey, std::move(automationId));
}
+ if(auto imageView = Toolkit::ImageView::DownCast(Self()))
+ {
+ auto imageSrc = FetchImageSrc(imageView);
+ if(!imageSrc.empty())
+ {
+ result.emplace(ATTR_IMG_SRC_KEY, std::move(imageSrc));
+ }
+ }
+
// Add "class" if not present already
if(result.find(classKey) == result.end())
{
bool ControlAccessible::ClearHighlight()
{
- Dali::Actor self = Self();
-
if(!Dali::Accessibility::IsUp())
{
return false;
}
- if(GetCurrentlyHighlightedActor() == self)
+ if(IsHighlighted())
{
UnregisterPropertySetSignal();
UnregisterPositionPropertyNotification();
- self.Remove(mCurrentHighlightActor.GetHandle());
+ Self().Remove(mCurrentHighlightActor.GetHandle());
mCurrentHighlightActor = {};
SetCurrentlyHighlightedActor({});
EmitHighlighted(false);
#define DALI_TOOLKIT_DEVEL_CONTROL_DEPTH_INDEX_RANGES_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
// The negative value for background effect and background has been
// chosen so that newer controls can have content without setting
// depth index, and go in front of native controls with a background.
-// This backround negative value means that the highest possible value
-// is SIBLING_ORDER_MULTIPLIER-BACKGROUND_EFFECT-1. The divisor of
-// 100 ensures the range fits within the sibling order range, and has
-// enough gaps to allow Control Authors to use other intermediate depths.
+// The lowest possible value is MINIMUM_DEPTH_INDEX, and highest possible
+// value is MAXIMUM_DEPTH_INDEX. The divisor of 10 ensures the range fits
+// within the sibling order range, and has enough gaps to allow Control
+// Authors to use other intermediate depths.
+//
+// Note : AUTO_INDEX is special value. It means that the depth index will be
+// automatically assigned when we register visual into the control.
+// Other values will be clamped to the range.
enum Ranges
{
- BACKGROUND_EFFECT = -2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
- BACKGROUND = -1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
- CONTENT = 0,
- DECORATION = 1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
- FOREGROUND_EFFECT = 2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100
+ MINIMUM_DEPTH_INDEX = -5 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10 + 1,
+ BACKGROUND_EFFECT = -2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+ BACKGROUND = -1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+ CONTENT = 0,
+ DECORATION = 1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+ FOREGROUND_EFFECT = 2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+ MAXIMUM_DEPTH_INDEX = 5 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+
+ AUTO_INDEX = MINIMUM_DEPTH_INDEX - 1, ///< Special value to indicate that the depth index should be automatically calculated.
+ /// If visual replaced by another visual, the depth index of the new visual will be set to previous visual.
+ /// Otherwise, depth index will be set as the maximum depth index + 1
+ /// what given control already has, or CONTENT if no visuals.
};
static_assert((unsigned int)DevelLayer::ACTOR_DEPTH_MULTIPLIER > (unsigned int)DevelLayer::SIBLING_ORDER_MULTIPLIER);
+static_assert(MINIMUM_DEPTH_INDEX < BACKGROUND_EFFECT);
static_assert(BACKGROUND_EFFECT < BACKGROUND);
static_assert(BACKGROUND < CONTENT);
static_assert(CONTENT < DECORATION);
static_assert(DECORATION < FOREGROUND_EFFECT);
+static_assert(FOREGROUND_EFFECT < MAXIMUM_DEPTH_INDEX);
+
+// AUTO_INDEX should not be inside of the valid range.
+static_assert(!(MINIMUM_DEPTH_INDEX <= AUTO_INDEX && AUTO_INDEX <= MAXIMUM_DEPTH_INDEX));
} // namespace DepthIndex
#define DALI_TOOLKIT_CONTROL_DEVEL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*
* @note Derived class should not call visual.SetOnScene(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
* Use below API with enabled set to false if derived class wishes to control when visual is staged.
- * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
- * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ * @note depth-index be used to Dali::Toolkit::DepthIndex::Ranges::AUTO_INDEX.
*/
DALI_TOOLKIT_API void RegisterVisual(Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual);
* @param[in] control The control
* @param[in] index The Property index of the visual, used to reference visual
* @param[in] visual The visual to register
- * @param[in] depthIndex The visual's depth-index is set to this
+ * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+ * the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+ * Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
*
* @note Derived class should not call visual.SetOnScene(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
* Use below API with enabled set to false if derived class wishes to control when visual is staged.
* @param[in] visual The visual to register
* @param[in] enabled false if derived class wants to control when visual is set on stage.
*
- * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
- * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ * @note depth-index be used to Dali::Toolkit::DepthIndex::Ranges::AUTO_INDEX.
*
* @see EnableVisual()
*/
* @param[in] index The Property index of the visual, used to reference visual
* @param[in] visual The visual to register
* @param[in] enabled false if derived class wants to control when visual is set on stage.
- * @param[in] depthIndex The visual's depth-index is set to this
+ * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+ * the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+ * Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
*
* @see EnableVisual()
* @see Visual::Base::GetDepthIndex()
GetImpl(textEditor).PasteText();
}
+void SetRemoveFrontInset(TextEditor textEditor, const bool remove)
+{
+ GetImpl(textEditor).SetRemoveFrontInset(remove);
+}
+
+bool IsRemoveFrontInset(TextEditor textEditor)
+{
+ return GetImpl(textEditor).IsRemoveFrontInset();
+}
+
+void SetRemoveBackInset(TextEditor textEditor, const bool remove)
+{
+ GetImpl(textEditor).SetRemoveBackInset(remove);
+}
+
+bool IsRemoveBackInset(TextEditor textEditor)
+{
+ return GetImpl(textEditor).IsRemoveBackInset();
+}
+
} // namespace DevelTextEditor
} // namespace Toolkit
* @see Dali::Toolkit::TextSelectionPopup::Property
*/
SELECTION_POPUP_STYLE,
+
+ /**
+ * @brief Whether to trim the xBearing of first glyph of the text.
+ * @details Name "removeFrontInset", type Property::BOOLEAN.
+ */
+ REMOVE_FRONT_INSET,
+
+ /**
+ * @brief Whether to trim the advance of last glyph of the text.
+ * @details Name "removeBackInset", type Property::BOOLEAN.
+ */
+ REMOVE_BACK_INSET,
};
} // namespace Property
*/
DALI_TOOLKIT_API void PasteText(TextEditor textEditor);
+/**
+ * @brief Set removing front inset to text label.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @param[in] remove Whether front inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveFrontInset(TextEditor textEditor, const bool remove);
+
+/**
+ * @brief Whether front inset of text label is removed or not.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @return True if the front inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveFrontInset(TextEditor textEditor);
+
+/**
+ * @brief Set removing back inset to text label.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @param[in] remove Whether back inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveBackInset(TextEditor textEditor, const bool remove);
+
+/**
+ * @brief Whether back inset of text label is removed or not.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @return True if the back inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveBackInset(TextEditor textEditor);
+
+
} // namespace DevelTextEditor
} // namespace Toolkit
GetImpl(textField).PasteText();
}
+void SetRemoveFrontInset(TextField textField, const bool remove)
+{
+ GetImpl(textField).SetRemoveFrontInset(remove);
+}
+
+bool IsRemoveFrontInset(TextField textField)
+{
+ return GetImpl(textField).IsRemoveFrontInset();
+}
+
+void SetRemoveBackInset(TextField textField, const bool remove)
+{
+ GetImpl(textField).SetRemoveBackInset(remove);
+}
+
+bool IsRemoveBackInset(TextField textField)
+{
+ return GetImpl(textField).IsRemoveBackInset();
+}
+
} // namespace DevelTextField
} // namespace Toolkit
* @see Dali::Toolkit::TextSelectionPopup::Property
*/
SELECTION_POPUP_STYLE,
+
+ /**
+ * @brief Whether to trim the xBearing of first glyph of the text.
+ * @details Name "removeFrontInset", type Property::BOOLEAN.
+ */
+ REMOVE_FRONT_INSET,
+
+ /**
+ * @brief Whether to trim the advance of last glyph of the text.
+ * @details Name "removeBackInset", type Property::BOOLEAN.
+ */
+ REMOVE_BACK_INSET,
};
} // namespace Property
*/
DALI_TOOLKIT_API void PasteText(TextField textField);
+/**
+ * @brief Set removing front inset to TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @param[in] remove Whether front inset of TextField has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveFrontInset(TextField textField, const bool remove);
+
+/**
+ * @brief Whether front inset of TextField is removed or not.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return True if the front inset of TextField is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveFrontInset(TextField textField);
+
+/**
+ * @brief Set removing back inset to TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @param[in] remove Whether back inset of TextField has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveBackInset(TextField textField, const bool remove);
+
+/**
+ * @brief Whether back inset of TextField is removed or not.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return True if the back inset of TextField is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveBackInset(TextField textField);
+
} // namespace DevelTextField
} // namespace Toolkit
* @details Name "removeBackInset", type Property::BOOLEAN.
*/
REMOVE_BACK_INSET,
+
+ /**
+ * @brief Whether to make the elements transparent, such as background or outline behind the text.
+ * @details Name "cutout", type Property::BOOLEAN.
+ */
+ CUTOUT,
};
} // namespace Property
* @details Name "width", type Property::STRING or Property::FLOAT i.e. "1.0" or 1.f
* @note Optional. If not provided then the outline is not enabled.
*/
- WIDTH
+ WIDTH,
+
+ /**
+ * @brief The offset in pixels of the outline.
+ * @details Name "offset", type Property::STRING or Property::VECTOR2. i.e "3.0 3.0" or Vector2( 3.f, 3.f )
+ * @note Optional. If not provided then the outline is not enabled.
+ */
+ OFFSET,
+
+ /**
+ * @brief The radius of the Gaussian blur for the outline.
+ * @details Name "blurRadius", type Property::STRING or Property::FLOAT. i.e "5.0" or 5.f
+ * @note Optional. If not provided then the outline is not enabled.
+ */
+ BLUR_RADIUS
};
} // namespace Property
#define DALI_TOOLKIT_TEXT_RANGE_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow Range to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Range> : public BasicTypes<Dali::Toolkit::Text::Range>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_TEXT_RANGE_H
#define DALI_TOOLKIT_TEXT_BASE_SPAN_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow BaseSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::BaseSpan> : public BasicTypes<Dali::Toolkit::Text::BaseSpan>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_TEXT_BASE_SPAN_H
#ifndef DALI_TOOLKIT_VISUAL_BASE_H
#define DALI_TOOLKIT_VISUAL_BASE_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
* @brief Set the depth index of this visual.
*
* Depth-index controls draw-order for overlapping visuals.
- * Visuals with higher depth indices are rendered in front of other visual with smaller values
+ * Visuals with higher depth indices are rendered in front of other visual with smaller values.
+ *
+ * @note The value of index will be clamped between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and
+ * DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
+ * @note If we call this API at least 1 time, we cannot set as DepthIndex::AUTO_INDEX after.
*
* @param[in] index The depth index of this visual.
*/
void SetDepthIndex(int index);
/**
- * @brief Get the depth index of this visual
+ * @brief Get the depth index of this visual which clamped between
+ * DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
+ * Or DepthIndex::Ranges::AUTO_INDEX if we never set depth index before.
*
* @return The depth index of this visual.
*/
#define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
/**
* @brief Whether to AnimatedVectorImageVisual fixed cache or not.
- * @details Name "EnableFrameCache", type Property::BOOLEAN.
+ * @details Name "enableFrameCache", type Property::BOOLEAN.
* If this property is true, AnimatedVectorImageVisual enable frame cache for loading and keeps loaded frame
* until the visual is removed. It reduces CPU cost when the animated image will be looping.
* But it can spend a lot of memory if the resource has high resolution image or many frame count.
- * @note It is used in the AnimatedImageVisual. The default is false
+ * @note It is used in the AnimatedVectorImageVisual. The default is false
*/
- ENABLE_FRAME_CACHE = ORIENTATION_CORRECTION + 16
+ ENABLE_FRAME_CACHE = ORIENTATION_CORRECTION + 16,
+
+ /**
+ * @brief Whether notify AnimatedVectorImageVisual to render thread after every rasterization or not.
+ * @details Name "notifyAfterRasterization", type Property::BOOLEAN.
+ * If this property is true, AnimatedVectorImageVisual send notify to render thread after every rasterization.
+ * If false, AnimatedVectorImageVisual set Renderer's Behaviour as Continouly (mean, always update the render thread.)
+ *
+ * This flag is useful if given resource has low fps, so we don't need to render every frame.
+ * @note It is used in the AnimatedVectorImageVisual. The default is false.
+ */
+ NOTIFY_AFTER_RASTERIZATION = ORIENTATION_CORRECTION + 17
};
} //namespace Property
{
DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
- DeleteNodesWithoutSelf otherDeletor(mNode);
+ CollectNodes collector;
- DepthFirst(mNode, otherDeletor);
+ DepthFirst(mNode, collector);
+
+ for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
+ {
+ if(*iter != mNode)
+ {
+ delete *iter;
+ }
+ }
mNode->mFirstChild = NULL;
mNode->mLastChild = NULL;
};
/*
- * Delete nodes immediately, instead of self
- */
-struct DeleteNodesWithoutSelf
-{
- DeleteNodesWithoutSelf(TreeNode* self)
- : mSelf(self){};
-
- /*
- * Call operator to delete object if given node is not self
- */
- void operator()(TreeNode*& n)
- {
- DALI_ASSERT_DEBUG(n && "Operation on NULL JSON node");
- if(mSelf != n)
- {
- delete n;
- }
- }
-
- const TreeNode* mSelf; ///< self node what we should not remove.
-};
-
-/*
* Depth first walk of nodes applying given operation (unary_function)
*/
template<typename Operation>
void CheckBoxButton::OnStateChange(State newState)
{
// TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
- if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+ if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
{
auto* accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0);
}
void PushButton::OnStateChange(State newState)
{
// TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
- if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+ if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
{
auto* accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitStateChanged(Dali::Accessibility::State::PRESSED, newState == SELECTED_STATE ? 1 : 0, 0);
}
// TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
- if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+ if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
{
auto* accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0);
}
DevelControl::UnregisterVisual(*this, index);
}
- DevelControl::RegisterVisual(*this, index, visual, enabled);
+ DevelControl::RegisterVisual(*this, index, visual, enabled, DepthIndex::CONTENT);
}
void ToggleButton::RelayoutVisual(Property::Index index, const Vector2& size)
void ToggleButton::OnStateChange(State newState)
{
// TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
- if((Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+ if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
{
auto* accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, mCurrentToggleIndex ? 1 : 0, 0);
accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
requiredDepthIndex = depthIndex;
}
+ // Change the depth index value automatically if the visual has DepthIndex to AUTO_INDEX
+ // or if RegisterVisual set DepthIndex to AUTO_INDEX.
+ const bool requiredDepthIndexChanged = (requiredDepthIndex == DepthIndex::AUTO_INDEX);
+
// Visual replacement, existing visual should only be removed from stage when replacement ready.
if(!mVisuals.Empty())
{
mVisuals.Erase(registeredVisualsiter);
}
- // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
- if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
- (visual.GetDepthIndex() == 0))
+ // If the visual have a depth index as AUTO_INDEX and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
+ if(requiredDepthIndexChanged)
{
requiredDepthIndex = currentDepthIndex;
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use replaced visual index. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
}
}
if(!visualReplaced) // New registration entry
{
- // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
- if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
- (mVisuals.Size() > 0) &&
- (visual.GetDepthIndex() == 0))
+ // If we have more than one visual and the visual have a depth index as AUTO_INDEX, then set it to be the highest
+ if((mVisuals.Size() > 0) && requiredDepthIndexChanged)
{
- int maxDepthIndex = std::numeric_limits<int>::min();
+ int maxDepthIndex = static_cast<int>(DepthIndex::CONTENT) - 1; // Start at DepthIndex::CONTENT if maxDepth index belongs to a background or no visuals have been added yet.
RegisteredVisualContainer::ConstIterator iter;
const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
maxDepthIndex = visualDepthIndex;
}
}
- ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top
- requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
+ requiredDepthIndex = ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top.
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use top of all visuals. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
}
}
if(visual)
{
+ // If required depth index still DepthIndex::AUTO_INDEX, Make it as DepthIndex::CONTENT now
+ if(requiredDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
+ {
+ requiredDepthIndex = static_cast<int>(DepthIndex::CONTENT);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Some strange cases. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
+ }
+
// Set determined depth index
visual.SetDepthIndex(requiredDepthIndex);
TransitionData::Animator* animator = (*iter);
Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
-
if(visual)
{
#if defined(DEBUG_ENABLED)
}
animation.AnimateTo(Property(child, propertyIndex),
- animator->targetValue,
- animator->alphaFunction,
- TimePeriod(animator->timePeriodDelay,
- animator->timePeriodDuration));
+ animator->targetValue,
+ animator->alphaFunction,
+ TimePeriod(animator->timePeriodDelay,
+ animator->timePeriodDuration));
}
}
}
#define DALI_TOOLKIT_CONTROL_DATA_IMPL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*/
// EXTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/public-api/object/property-notification.h>
#include <dali/public-api/object/type-registry.h>
#include <string>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
#include <dali-toolkit/internal/builder/dictionary.h>
#include <dali-toolkit/internal/builder/style.h>
* @param[in,out] visual The visual to register, which can be altered in this function
* @param[in] enabled false if derived class wants to control when visual is set on stage
* @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
- * @param[in] depthIndex The visual's depth-index is set to this
+ * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+ * the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+ * Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
*
* @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
* occur once the replacement visual is ready (loaded).
*/
- void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = 0);
+ void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = static_cast<int>(Toolkit::DepthIndex::AUTO_INDEX));
/**
* @brief Emits the resource ready signal.
// the designed behaviour of GlView so signal is connected regardless
if(window)
{
+ mPlacementWindow = window;
DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
}
}
Control::OnSceneDisconnection();
mNativeRenderer->Terminate();
+
+ Window window = mPlacementWindow.GetHandle();
+ if(window)
+ {
+ DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &DrawableView::OnWindowVisibilityChanged);
+ mPlacementWindow.Reset();
+ }
}
void DrawableView::AddRenderer()
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/object/weak-handle.h>
#include <dali/public-api/rendering/geometry.h>
#include <dali/public-api/rendering/shader.h>
#include <dali/public-api/signals/render-callback.h>
bool OnRenderCallback(const RenderCallbackInput& renderCallbackInput);
private:
+ WeakHandle<Window> mPlacementWindow;
Dali::Toolkit::GlView::RenderingMode mRenderingMode;
bool mDepth;
}
//Adding VisibilityChange Signal.
- Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &GlView::OnControlVisibilityChanged);
+ self.InheritedVisibilityChangedSignal().Connect(this, &GlView::OnControlInheritedVisibilityChanged);
}
void GlView::OnSizeSet(const Vector3& targetSize)
return Shader::New(SHADER_GL_VIEW_VERT, fragmentShader, Shader::Hint::NONE, "GL_VIEW");
}
-void GlView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
+void GlView::OnControlInheritedVisibilityChanged(Dali::Actor actor, bool visible)
{
Actor self = Self();
- if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+ if(mRenderThread)
{
- if(mRenderThread)
+ if(visible && DevelWindow::Get(self).IsVisible())
+ {
+ mRenderThread->Resume();
+ }
+ else
{
- if(visible && DevelWindow::Get(self).IsVisible())
- {
- mRenderThread->Resume();
- }
- else
- {
- mRenderThread->Pause();
- }
+ mRenderThread->Pause();
}
}
}
if(window)
{
+ mPlacementWindow = window;
DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged);
}
-
- if(mRenderThread)
- {
- if(self.GetProperty<bool>(Actor::Property::VISIBLE) && window.IsVisible())
- {
- mRenderThread->Resume();
- }
- }
}
void GlView::OnSceneDisconnection()
{
Control::OnSceneDisconnection();
- if(mRenderThread)
+ Window window = mPlacementWindow.GetHandle();
+ if(window)
{
- mRenderThread->Pause();
+ DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &GlView::OnWindowVisibilityChanged);
+ mPlacementWindow.Reset();
}
}
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/object/weak-handle.h>
#include <dali/public-api/rendering/geometry.h>
#include <dali/public-api/rendering/shader.h>
GlView& operator=(const GlView& GlView);
/**
- * Callback when the visibility of the GlView is changed
+ * Callback when the inherited visibility of the GlView is changed
*/
- void OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type);
+ void OnControlInheritedVisibilityChanged(Dali::Actor actor, bool visible);
/**
* Callback when the visibility of the window is changed
Dali::NativeImageSourceQueue::ColorFormat GetColorFormat(Dali::Toolkit::GlView::ColorFormat format);
private:
+ WeakHandle<Window> mPlacementWindow;
std::unique_ptr<GlViewRenderThread> mRenderThread;
Dali::NativeImageSourceQueuePtr mNativeImageQueue;
Dali::Toolkit::GlView::RenderingMode mRenderingMode;
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/public-api/object/type-registry.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
{
const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
-constexpr float FULL_OPACITY = 1.0f;
-constexpr float LOW_OPACITY = 0.2f;
+constexpr float FULL_OPACITY = 1.0f;
+constexpr float LOW_OPACITY = 0.2f;
constexpr float TRANSITION_EFFECT_SPEED = 0.3f;
-constexpr int PLACEHOLDER_DEPTH_INDEX = -2;
-constexpr int PREVIOUS_VISUAL_DEPTH_INDEX = -1;
-constexpr int CURRENT_VISUAL_DEPTH_INDEX = 0;
+constexpr int PLACEHOLDER_DEPTH_INDEX = -2;
+constexpr int PREVIOUS_VISUAL_DEPTH_INDEX = -1;
+constexpr int CURRENT_VISUAL_DEPTH_INDEX = 0;
BaseHandle Create()
{
DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA)
DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "placeholderImage", STRING, PLACEHOLDER_IMAGE)
DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "enableTransitionEffect", BOOLEAN, ENABLE_TRANSITION_EFFECT)
+DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "transitionEffectOption", MAP, TRANSITION_EFFECT_OPTION)
DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA)
DALI_TYPE_REGISTRATION_END()
visualImpl.SetCustomShader(mShaderMap);
}
- DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+ DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
}
else
{
mPreviousVisual = mVisual;
}
-
-
// Don't bother comparing if we had a visual previously, just drop old visual and create new one
mUrl = url;
mImageSize = size;
visualImpl.SetCustomShader(mShaderMap);
}
- DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+ DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
}
else
{
return mTransitionEffect;
}
+void ImageView::SetTransitionEffectOption(const Property::Map& map)
+{
+ mTransitionEffectOptionMap = map;
+}
+
Vector3 ImageView::GetNaturalSize()
{
if(mVisual)
bool zeroPadding = (padding == Extents());
Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
- Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
{
std::swap(padding.start, padding.end);
mPreviousVisual.SetDepthIndex(mPreviousVisual.GetDepthIndex() + PREVIOUS_VISUAL_DEPTH_INDEX);
}
- mTransitionAnimation = Animation::New(TRANSITION_EFFECT_SPEED);
- mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
- float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
-
// Transition current image
Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
if(imageVisual)
{
- Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
- fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
- fadeinKeyFrames.Add(1.0f, destinationAlpha);
- mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames, AlphaFunction::EASE_IN_OUT);
imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX);
- }
+ if(!mTransitionEffectOptionMap.Empty())
+ {
+ // Set user's transition effect options
+ Dali::Toolkit::TransitionData transition = Toolkit::TransitionData::New(mTransitionEffectOptionMap);
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
+ mTransitionAnimation = controlDataImpl.CreateTransition(transition);
+ if(mTransitionAnimation)
+ {
+ mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
+ mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
+ mTransitionAnimation.Play();
+ }
+ else
+ {
+ DALI_LOG_ERROR("Create Transition Animation failed");
+ }
+ }
+ else
+ {
+ mTransitionAnimation = Animation::New(TRANSITION_EFFECT_SPEED);
+ mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
+ float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
+
+ // Transition current image
+ Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
+ if(imageVisual)
+ {
+ Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
+ fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
+ fadeinKeyFrames.Add(1.0f, destinationAlpha);
+ mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames, AlphaFunction::EASE_IN_OUT);
+ imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX);
+ }
- // Play transition animation
- mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
- mTransitionAnimation.Play();
+ // Play transition animation
+ mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
+ mTransitionAnimation.Play();
+ }
+ }
}
}
}
break;
}
+ case Toolkit::ImageView::Property::TRANSITION_EFFECT_OPTION:
+ {
+ Property::Map map;
+ if(value.Get(map))
+ {
+ impl.SetTransitionEffectOption(map);
+ }
+ }
}
}
}
bool IsTransitionEffectEnabled() const;
/**
+ * @brief Set the transition effect option.
+ */
+ void SetTransitionEffectOption(const Property::Map& map);
+
+ /**
* @brief callback when animation for placeholder or previous visual transition effect is finished
*/
void OnTransitionAnimationFinishedCallback(Animation& animation);
std::string mPlaceholderUrl; ///< the url for the placeholder image if the image came from a PLACEHOLDER_IMAGE, empty otherwise
Property::Map mPropertyMap; ///< the Property::Map if the image came from a Property::Map, empty otherwise
Property::Map mShaderMap; ///< the Property::Map if the custom shader is set, empty otherwise
+ Property::Map mTransitionEffectOptionMap; ///< the Property::Map if the transition effect option is set, empty otherwise
ImageDimensions mImageSize; ///< the image size
Animation mTransitionAnimation; ///< the animation for transition effect
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h>
// EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
// Enum to make sure the visual order
enum
{
- TRACK_VISUAL,
+ TRACK_VISUAL = Toolkit::DepthIndex::CONTENT,
SECONDARY_PROGRESS_VISUAL,
PROGRESS_VISUAL,
LABEL_VISUAL,
Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast(Self());
mValueChangedSignal.Emit(self, mProgressValue, mSecondaryProgressValue);
- if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+ auto accessible = GetAccessibleObject();
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
- auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
- {
- accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
- }
+ accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
}
RelayoutRequest();
}
if(scrollableHandle)
{
mScrollPositionIntervalReachedSignal.Emit(scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition));
- if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+ auto accessible = GetAccessibleObject();
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
- auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
- {
- accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
- }
+ accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
}
}
}
{
mValue = value;
DisplayValue(mValue, true);
- if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+ auto accessible = GetAccessibleObject();
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
- auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
- {
- accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
- }
+ accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
}
}
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "relativeLineSize", FLOAT, RELATIVE_LINE_SIZE )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "verticalAlignment", STRING, VERTICAL_ALIGNMENT )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "selectionPopupStyle", MAP, SELECTION_POPUP_STYLE )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "removeFrontInset", BOOLEAN, REMOVE_FRONT_INSET )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "removeBackInset", BOOLEAN, REMOVE_BACK_INSET )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED )
void TextEditor::TextInserted(unsigned int position, unsigned int length, const std::string& content)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextInserted(position, length, content);
}
void TextEditor::TextDeleted(unsigned int position, unsigned int length, const std::string& content)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextDeleted(position, length, content);
}
void TextEditor::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextCursorMoved(newPosition);
}
mController->ChangedLayoutDirection();
}
+void TextEditor::SetRemoveFrontInset(bool remove)
+{
+ mController->SetRemoveFrontInset(remove);
+}
+
+bool TextEditor::IsRemoveFrontInset() const
+{
+ return mController->IsRemoveFrontInset();
+}
+
+void TextEditor::SetRemoveBackInset(bool remove)
+{
+ mController->SetRemoveBackInset(remove);
+}
+
+bool TextEditor::IsRemoveBackInset() const
+{
+ return mController->IsRemoveBackInset();
+}
+
TextEditor::TextEditor(ControlBehaviour additionalBehaviour)
: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour)),
mAnimationPeriod(0.0f, 0.0f),
*/
void AnchorClicked(const std::string& href) override;
+ /**
+ * @brief Set removing front inset to TextEditor.
+ *
+ * @param[in] remove Whether front inset of TextEditor has to be removed or not.
+ */
+ void SetRemoveFrontInset(const bool remove);
+
+ /**
+ * @brief Whether front inset of TextEditor is removed or not.
+ *
+ * @return True if the front inset of TextEditor is removed.
+ */
+ bool IsRemoveFrontInset() const;
+
+ /**
+ * @brief Set removing back inset to TextEditor.
+ *
+ * @param[in] remove Whether back inset of TextEditor has to be removed or not.
+ */
+ void SetRemoveBackInset(const bool remove);
+
+ /**
+ * @brief Whether back inset of TextEditor is removed or not.
+ *
+ * @return True if the back inset of TextEditor is removed.
+ */
+ bool IsRemoveBackInset() const;
+
private: // Implementation
/**
* @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
}
break;
}
+ case Toolkit::DevelTextEditor::Property::REMOVE_FRONT_INSET:
+ {
+ const bool remove = value.Get<bool>();
+ impl.mController->SetRemoveFrontInset(remove);
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::REMOVE_BACK_INSET:
+ {
+ const bool remove = value.Get<bool>();
+ impl.mController->SetRemoveBackInset(remove);
+ break;
+ }
}
}
value = map;
break;
}
+ case Toolkit::DevelTextEditor::Property::REMOVE_FRONT_INSET:
+ {
+ value = impl.mController->IsRemoveFrontInset();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::REMOVE_BACK_INSET:
+ {
+ value = impl.mController->IsRemoveBackInset();
+ break;
+ }
} //switch
return value;
}
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "inputStrikethrough", MAP, INPUT_STRIKETHROUGH )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "characterSpacing", FLOAT, CHARACTER_SPACING )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "selectionPopupStyle", MAP, SELECTION_POPUP_STYLE )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "removeFrontInset", BOOLEAN, REMOVE_FRONT_INSET )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "removeBackInset", BOOLEAN, REMOVE_BACK_INSET )
DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED )
void TextField::TextInserted(unsigned int position, unsigned int length, const std::string& content)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextInserted(position, length, content);
}
void TextField::TextDeleted(unsigned int position, unsigned int length, const std::string& content)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextDeleted(position, length, content);
}
void TextField::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
{
auto accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitTextCursorMoved(newPosition);
}
mController->SetSpannedText(spannedText);
}
+void TextField::SetRemoveFrontInset(bool remove)
+{
+ mController->SetRemoveFrontInset(remove);
+}
+
+bool TextField::IsRemoveFrontInset() const
+{
+ return mController->IsRemoveFrontInset();
+}
+
+void TextField::SetRemoveBackInset(bool remove)
+{
+ mController->SetRemoveBackInset(remove);
+}
+
+bool TextField::IsRemoveBackInset() const
+{
+ return mController->IsRemoveBackInset();
+}
+
std::string TextField::TextFieldAccessible::GetName() const
{
if(IsHiddenInput())
*/
void SetSpannedText(const Text::Spanned& spannedText);
+ /**
+ * @brief Set removing front inset to TextField.
+ *
+ * @param[in] remove Whether front inset of TextField has to be removed or not.
+ */
+ void SetRemoveFrontInset(const bool remove);
+
+ /**
+ * @brief Whether front inset of TextField is removed or not.
+ *
+ * @return True if the front inset of TextField is removed.
+ */
+ bool IsRemoveFrontInset() const;
+
+ /**
+ * @brief Set removing back inset to TextField.
+ *
+ * @param[in] remove Whether back inset of TextField has to be removed or not.
+ */
+ void SetRemoveBackInset(const bool remove);
+
+ /**
+ * @brief Whether back inset of TextField is removed or not.
+ *
+ * @return True if the back inset of TextField is removed.
+ */
+ bool IsRemoveBackInset() const;
+
private: // Implementation
/**
* @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
}
break;
}
+ case Toolkit::DevelTextField::Property::REMOVE_FRONT_INSET:
+ {
+ const bool remove = value.Get<bool>();
+ impl.mController->SetRemoveFrontInset(remove);
+ break;
+ }
+ case Toolkit::DevelTextField::Property::REMOVE_BACK_INSET:
+ {
+ const bool remove = value.Get<bool>();
+ impl.mController->SetRemoveBackInset(remove);
+ break;
+ }
}
}
value = map;
break;
}
+ case Toolkit::DevelTextField::Property::REMOVE_FRONT_INSET:
+ {
+ value = impl.mController->IsRemoveFrontInset();
+ break;
+ }
+ case Toolkit::DevelTextField::Property::REMOVE_BACK_INSET:
+ {
+ value = impl.mController->IsRemoveBackInset();
+ break;
+ }
+
} //switch
return value;
}
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
#include <dali-toolkit/public-api/visuals/visual-properties.h>
* The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
*/
const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
-{
+ {
0.0f, // VerticalAlignment::TOP
0.5f, // VerticalAlignment::CENTER
1.0f // VerticalAlignment::BOTTOM
#endif
const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
-{
+ {
{"IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE},
{"FINISH_LOOP", Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP},
};
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "anchorClickedColor", VECTOR4, ANCHOR_CLICKED_COLOR )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeFrontInset", BOOLEAN, REMOVE_FRONT_INSET )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeBackInset", BOOLEAN, REMOVE_BACK_INSET )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "cutout", BOOLEAN, CUTOUT )
DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0)
impl.mController->SetRemoveBackInset(remove);
break;
}
+ case Toolkit::DevelTextLabel::Property::CUTOUT:
+ {
+ const bool cutout = value.Get<bool>();
+
+ impl.mController->SetTextCutout(cutout);
+
+ // Property doesn't affect the layout, only Visual must be updated
+ TextVisual::EnableRendererUpdate(impl.mVisual);
+
+ // No need to trigger full re-layout. Instead call UpdateRenderer() directly
+ TextVisual::UpdateRenderer(impl.mVisual);
+ break;
+ }
}
// Request relayout when text update is needed. It's necessary to call it
value = impl.mController->IsRemoveBackInset();
break;
}
+ case Toolkit::DevelTextLabel::Property::CUTOUT:
+ {
+ value = impl.mController->IsTextCutout();
+ break;
+ }
}
}
propertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT);
mVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
- DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual);
+ DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual, DepthIndex::CONTENT);
TextVisual::SetAnimatableTextColorProperty(mVisual, Toolkit::TextLabel::Property::TEXT_COLOR);
CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
break;
}
+ case Toolkit::Control::Property::BACKGROUND:
+ {
+ const Vector4 backgroundColor = propertyValue.Get<Vector4>();
+
+ if(mController->IsTextCutout())
+ {
+ DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false);
+ mController->SetBackgroundWithCutoutEnabled(true);
+ mController->SetBackgroundColorWithCutout(backgroundColor);
+ }
+
+ break;
+ }
+ case Toolkit::DevelTextLabel::Property::CUTOUT:
+ {
+ const bool cutoutEnabled = propertyValue.Get<bool>();
+
+ if(cutoutEnabled)
+ {
+ Vector4 backgroundColor = Vector4::ZERO;
+
+ const Property::Map backgroundMap = Self().GetProperty(Toolkit::Control::Property::BACKGROUND).Get<Property::Map>();
+ Property::Value* backgroundValue = backgroundMap.Find(ColorVisual::Property::MIX_COLOR);
+ if(backgroundValue)
+ {
+ backgroundColor = backgroundValue->Get<Vector4>();
+ }
+
+ DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false);
+ mController->SetBackgroundWithCutoutEnabled(true);
+ mController->SetBackgroundColorWithCutout(backgroundColor);
+ }
+ else
+ {
+ DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, true);
+
+ Property::Map backgroundMapSet;
+ mController->SetBackgroundWithCutoutEnabled(false);
+ }
+
+ TextVisual::SetRequireRender(mVisual, cutoutEnabled);
+ break;
+ }
default:
{
Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
mLastAutoScrollEnabled = false;
}
- const Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = mTextScroller->GetStopMode();
- mTextScroller->SetStopMode(Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE);
- mTextScroller->StopScrolling();
- mTextScroller->SetStopMode(stopMode);
+ if(mTextScroller->IsScrolling())
+ {
+ const Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = mTextScroller->GetStopMode();
+ mTextScroller->SetStopMode(Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE);
+ mTextScroller->StopScrolling();
+ mTextScroller->SetStopMode(stopMode);
+ }
}
Control::OnSceneDisconnection();
}
{
DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout\n");
+ if(mTextScroller && mTextScroller->IsStop())
+ {
+ // When auto scroll is playing, it triggers a relayout only when an update is absolutely necessary.
+ return;
+ }
+
Actor self = Self();
Extents padding;
{
// Pure Virtual from TextScroller Interface
DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
-
- if(mController->IsAutoScrollEnabled() || !mController->IsMultiLineEnabled())
- {
- mController->SetAutoScrollEnabled(false);
- RequestTextRelayout();
- }
+ mController->SetAutoScrollEnabled(false);
+ RequestTextRelayout();
}
void TextLabel::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
#include <dali/public-api/object/type-registry.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/controls/web-view/web-back-forward-list.h>
#include <dali-toolkit/devel-api/controls/web-view/web-settings.h>
if(mVisual)
{
- DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual);
+ DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual, DepthIndex::CONTENT);
EnableBlendMode(!mVideoHoleEnabled);
}
}
-attribute mediump vec2 aPosition;
+attribute highp vec2 aPosition;
attribute mediump vec2 aTexCoord;
attribute mediump vec4 aColor;
uniform mediump vec2 uOffset;
void main()
{
- mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
+ highp vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
gl_Position = uMvpMatrix * position;
vTexCoord = aTexCoord;
vColor = aColor;
else if((controller.mImpl->mEventData->mPrimaryCursorPosition > 0) && (keyCode == Dali::DALI_KEY_BACKSPACE))
{
// Remove the character before the current cursor position
- removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE);
+ removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE, false);
}
else if((controller.mImpl->mEventData->mPrimaryCursorPosition < controller.mImpl->mModel->mLogicalModel->mText.Count()) &&
(keyCode == Dali::DevelKey::DALI_KEY_DELETE))
{
// Remove the character after the current cursor position
- removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE);
+ removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE, false);
}
if(removed)
const bool textDeleted = TextUpdater::RemoveText(controller,
inputMethodContextEvent.cursorOffset,
inputMethodContextEvent.numberOfChars,
- DONT_UPDATE_INPUT_STYLE);
+ DONT_UPDATE_INPUT_STYLE,
+ false);
if(textDeleted)
{
const char* EMPTY_STRING = "";
const char* MIME_TYPE_TEXT_PLAIN = "text/plain;charset=utf-8";
+const char* MIME_TYPE_HTML = "application/xhtml+xml";
} // namespace
return false;
}
+bool Controller::Impl::IsClipboardEmpty()
+{
+ bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && (mClipboard.HasType(MIME_TYPE_TEXT_PLAIN) || mClipboard.HasType(MIME_TYPE_HTML)));
+ return !result;
+}
+
void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
{
std::string selectedText;
mTextFitArrayEnabled(false),
mIsLayoutDirectionChanged(false),
mIsUserInteractionEnabled(true),
- mProcessorRegistered(false)
+ mProcessorRegistered(false),
+ mTextCutout(false)
{
mModel = Model::New();
return mClipboard != nullptr ? true : false;
}
- bool IsClipboardEmpty()
- {
- bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && mClipboard.NumberOfItems());
- return !result; // If NumberOfItems greater than 0, return false
- }
-
bool IsClipboardVisible()
{
bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && mClipboard.IsVisible());
}
/**
+ * @brief Whether the clipboard is empty or not.
+ * Checks the types that the text controller can paste and returns the result.
+ *
+ * @return Return whether or not the clipboard is empty.
+ */
+ bool IsClipboardEmpty();
+
+ /**
* @copydoc Controller::GetLayoutDirection()
*/
Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
bool mProcessorRegistered : 1; ///< Whether the text controller registered into processor or not.
+ bool mTextCutout : 1; ///< Whether the text cutout enabled.
private:
friend ControllerImplEventHandler;
removedPrevious = RemoveText(controller,
-static_cast<int>(eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition),
eventData->mPreEditLength,
- DONT_UPDATE_INPUT_STYLE);
+ DONT_UPDATE_INPUT_STYLE,
+ true);
eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition;
eventData->mPreEditLength = 0u;
Controller& controller,
int cursorOffset,
int numberOfCharacters,
- UpdateInputStyleType type)
+ UpdateInputStyleType type,
+ bool isDeletingPreEdit)
{
bool removed = false;
bool removeAll = false;
if(removeAll)
{
impl.ClearPreEditFlag();
- textUpdateInfo.mNumberOfCharactersToAdd = 0;
+ if(!isDeletingPreEdit)
+ {
+ textUpdateInfo.mNumberOfCharactersToAdd = 0;
+ }
}
// Updates the text style runs by removing characters. Runs with no characters are removed.
* @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
* @param[in] numberOfCharacters The number of characters to delete from the cursorOffset.
* @param[in] type Whether to update the input style.
+ * @param[in] isDeletingPreEdit Whether to remove pre-edit when inserting text.
* @return True if the remove was successful.
*/
- static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type);
+ static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type, bool isDeletingPreEdit);
/**
* @brief Checks if text is selected and if so removes it.
const char* EMPTY_STRING = "";
const char* MIME_TYPE_TEXT_PLAIN = "text/plain;charset=utf-8";
+const char* MIME_TYPE_HTML = "application/xhtml+xml";
template<typename Type>
void EnsureCreated(Type*& object)
mImpl->mModel->mRemoveBackInset = remove;
}
+bool Controller::IsTextCutout() const
+{
+ return mImpl->mTextCutout;
+}
+
+void Controller::SetTextCutout(bool cutout)
+{
+ if(cutout != mImpl->mTextCutout)
+ {
+ mImpl->mModel->mVisualModel->SetCutoutEnabled(cutout);
+ mImpl->mTextCutout = cutout;
+ mImpl->RequestRelayout();
+ }
+}
+
void Controller::ChangedLayoutDirection()
{
mImpl->mIsLayoutDirectionChanged = true;
return mImpl->mModel->mVisualModel->GetDashedUnderlineGap();
}
+void Controller::SetOutlineOffset(const Vector2& outlineOffset)
+{
+ mImpl->mModel->mVisualModel->SetOutlineOffset(outlineOffset);
+ mImpl->RequestRelayout();
+}
+
+const Vector2& Controller::GetOutlineOffset() const
+{
+ return mImpl->mModel->mVisualModel->GetOutlineOffset();
+}
+
void Controller::SetOutlineColor(const Vector4& color)
{
mImpl->mModel->mVisualModel->SetOutlineColor(color);
return mImpl->mModel->mVisualModel->GetOutlineWidth();
}
+void Controller::SetOutlineBlurRadius(const float& outlineBlurRadius)
+{
+ if(fabsf(GetOutlineBlurRadius() - outlineBlurRadius) > Math::MACHINE_EPSILON_1)
+ {
+ mImpl->mModel->mVisualModel->SetOutlineBlurRadius(outlineBlurRadius);
+ mImpl->RequestRelayout();
+ }
+}
+
+const float& Controller::GetOutlineBlurRadius() const
+{
+ return mImpl->mModel->mVisualModel->GetOutlineBlurRadius();
+}
+
void Controller::SetBackgroundColor(const Vector4& color)
{
mImpl->mModel->mVisualModel->SetBackgroundColor(color);
mImpl->mModel->mVisualTransformOffset = offset;
}
+void Controller::SetBackgroundWithCutoutEnabled(bool cutout)
+{
+ mImpl->mModel->mVisualModel->SetBackgroundWithCutoutEnabled(cutout);
+ RequestRelayout();
+}
+
+bool Controller::IsBackgroundWithCutoutEnabled() const
+{
+ return mImpl->mModel->mVisualModel->IsBackgroundWithCutoutEnabled();
+}
+
+void Controller::SetBackgroundColorWithCutout(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetBackgroundColorWithCutout(color);
+ mImpl->RequestRelayout();
+}
+
+const Vector4 Controller::GetBackgroundColorWithCutout() const
+{
+ return mImpl->mModel->mVisualModel->GetBackgroundColorWithCutout();
+}
+
Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
{
return Relayouter::Relayout(*this, size, layoutDirection);
mImpl->mClipboard.DataReceivedSignal().Disconnect(this, &Controller::PasteClipboardItemEvent);
// If the id is 0u, it is an invalid response.
+ if(id == 0u)
+ {
+ return;
+ }
+
// text-controller allows only plain text type.
- if(id != 0u && !strncmp(mimeType, MIME_TYPE_TEXT_PLAIN, strlen(MIME_TYPE_TEXT_PLAIN)))
+ if(!strncmp(mimeType, MIME_TYPE_TEXT_PLAIN, strlen(MIME_TYPE_TEXT_PLAIN)))
{
EventHandler::PasteClipboardItemEvent(*this, data);
}
+ else if(!strncmp(mimeType, MIME_TYPE_HTML, strlen(MIME_TYPE_HTML)))
+ {
+ // This does not mean that text controls can parse html.
+ // This is temporary code, as text controls do not support html type data.
+ // Simply remove the tags inside the angle brackets.
+ // Once multiple types and data can be stored in the clipboard, this code should be removed.
+ std::regex reg("<[^>]*>");
+ std::string result = regex_replace(data, reg, "");
+
+ EventHandler::PasteClipboardItemEvent(*this, result.c_str());
+ }
}
void Controller::PasteText()
// Connect the signal before calling GetData() of the clipboard.
mImpl->mClipboard.DataReceivedSignal().Connect(this, &Controller::PasteClipboardItemEvent);
+ // If there is no plain text type data on the clipboard, request html type data.
+ std::string mimeType = mImpl->mClipboard.HasType(MIME_TYPE_TEXT_PLAIN) ? MIME_TYPE_TEXT_PLAIN : MIME_TYPE_HTML;
+
// Request clipboard service to retrieve an item.
- uint id = mImpl->mClipboard.GetData(MIME_TYPE_TEXT_PLAIN);
+ uint id = mImpl->mClipboard.GetData(mimeType);
if(id == 0u)
{
// If the return id is 0u, the signal is not emitted, we must disconnect signal here.
float GetDashedUnderlineGap() const;
/**
+ * @brief Set the outline offset.
+ *
+ * @param[in] outlineOffset The outline offset.
+ */
+ void SetOutlineOffset(const Vector2& outlineOffset);
+
+ /**
+ * @brief Retrieve the outline offset.
+ *
+ * @return The outline offset.
+ */
+ const Vector2& GetOutlineOffset() const;
+
+ /**
* @brief Set the outline color.
*
* @param[in] color color of outline.
uint16_t GetOutlineWidth() const;
/**
+ * @brief Set the outline blur radius.
+ *
+ * @param[in] outlineBlurRadius The outline blur radius, 0,0 indicates no blur.
+ */
+ void SetOutlineBlurRadius(const float& outlineBlurRadius);
+
+ /**
+ * @brief Retrieve the outline blur radius.
+ *
+ * @return The outline blur radius.
+ */
+ const float& GetOutlineBlurRadius() const;
+
+ /**
* @brief Set the background color.
*
* @param[in] color color of background.
*/
void SetVisualTransformOffset(Vector2 offset);
+ /**
+ * @brief Sets whether background color with cutout is enabled.
+ *
+ * @param[in] enable True if enabled.
+ */
+ void SetBackgroundWithCutoutEnabled(bool enable);
+
+ /**
+ * @brief Whether background color with cutout is enabled.
+ *
+ * @return True if enabled.
+ */
+ bool IsBackgroundWithCutoutEnabled() const;
+
+ /**
+ * @brief Sets whether background color with cutout.
+ *
+ * @param[in] color The color to set.
+ */
+ void SetBackgroundColorWithCutout(const Vector4& color);
+
+ /**
+ * @brief Retrieves background color with cutout.
+ *
+ * @return The color.
+ */
+ const Vector4 GetBackgroundColorWithCutout() const;
+
public: // Queries & retrieves.
/**
* @brief Return the layout engine.
void SetRemoveBackInset(bool remove);
/**
+ * @brief Retrieves cutout value to model
+ * @return The value of cutout for the text
+ */
+ bool IsTextCutout() const;
+
+ /**
+ * @brief Sets cutout value to model
+ * @param[in] cutout The value of cutout for the text
+ */
+ void SetTextCutout(bool cutout);
+
+ /**
* @brief Sets SetMatchLayoutDirection value to model
* @param[in] match The value of matchLayoutDirection for the text
*/
#define DALI_TOOLKIT_TEXT_GLYPH_RUN_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*/
struct GlyphRun
{
- GlyphIndex glyphIndex; ///< Index to the first glyph.
- Length numberOfGlyphs; ///< Number of glyphs in the run.
+ GlyphIndex glyphIndex{0u}; ///< Index to the first glyph.
+ Length numberOfGlyphs{0u}; ///< Number of glyphs in the run.
};
} // namespace Text
#define DALI_TOOLKIT_TEXT_LINE_RUN_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*/
struct LineRun
{
- GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs of the run.
- CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
- float width; ///< The line's width.
- float ascender; ///< The line's ascender.
- float descender; ///< The line's descender.
- float extraLength; ///< The length of the white spaces at the end of the line.
- float alignmentOffset; ///< The horizontal alignment offset.
- float lineSpacing; ///< The line's spacing
- CharacterDirection direction : 1; ///< Direction of the first character of the paragraph.
- bool ellipsis : 1; ///< Wheter ellipsis is added to the line.
- bool isSplitToTwoHalves; ///< Whether the second half is defined. When split line to two halves to set Ellipsis in the MIDDLE of line. The second half is the second part of line after Ellipsis.
- GlyphRun glyphRunSecondHalf; ///< The initial glyph index and the number of glyphs of the run for the second half of line.
- CharacterRun characterRunForSecondHalfLine; ///< The initial character index and the number of characters of the run for the second half of line.
+ GlyphRun glyphRun{}; ///< The initial glyph index and the number of glyphs of the run.
+ CharacterRun characterRun{}; ///< The initial character index and the number of characters of the run.
+ float width; ///< The line's width.
+ float ascender; ///< The line's ascender.
+ float descender; ///< The line's descender.
+ float extraLength; ///< The length of the white spaces at the end of the line.
+ float alignmentOffset; ///< The horizontal alignment offset.
+ float lineSpacing; ///< The line's spacing
+ CharacterDirection direction : 1; ///< Direction of the first character of the paragraph.
+ bool ellipsis : 1; ///< Wheter ellipsis is added to the line.
+ bool isSplitToTwoHalves; ///< Whether the second half is defined. When split line to two halves to set Ellipsis in the MIDDLE of line. The second half is the second part of line after Ellipsis.
+ GlyphRun glyphRunSecondHalf{}; ///< The initial glyph index and the number of glyphs of the run for the second half of line.
+ CharacterRun characterRunForSecondHalfLine{}; ///< The initial character index and the number of characters of the run for the second half of line.
};
/**
const bool underlineEnabled = view.IsUnderlineEnabled();
const uint16_t outlineWidth = view.GetOutlineWidth();
const Vector4& outlineColor(view.GetOutlineColor());
+ const Vector2& outlineOffset(view.GetOutlineOffset());
const bool isOutline = 0u != outlineWidth;
const GlyphInfo* hyphens = view.GetHyphens();
const Length* hyphenIndices = view.GetHyphenIndices();
if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
{
- Vector2 positionPlusOutlineOffset = position;
+ Vector2 positionPlusOutlineOffset = position + outlineOffset;
if(isOutline)
{
// Add an offset to the text.
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
// EXTERNAL INCLUDES
+#include <cmath>
#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
#include <dali/integration-api/trace.h>
#include <dali/public-api/common/constants.h>
#include <dali/public-api/math/math-utils.h>
const Vector2* const positionBuffer = model->GetLayout();
const Vector4* const backgroundColorsBuffer = model->GetBackgroundColors();
const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
+ const bool removeFrontInset = model->IsRemoveFrontInset();
+ const bool removeBackInset = model->IsRemoveBackInset();
const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment();
}
// Calculate the positions of leftmost and rightmost glyphs in the current line
- if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+ if(removeFrontInset)
{
- left = position->x - glyphInfo->xBearing;
+ if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+ {
+ left = position->x;
+ }
+ }
+ else
+ {
+ const float originPositionLeft = position->x - glyphInfo->xBearing;
+ if((originPositionLeft < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+ {
+ left = originPositionLeft;
+ }
}
- if(position->x + glyphInfo->width > right)
+ if(removeBackInset)
{
- right = position->x - glyphInfo->xBearing + glyphInfo->advance;
+ if(position->x + glyphInfo->width > right)
+ {
+ right = position->x - position->x + glyphInfo->width;
+ }
+ }
+ else
+ {
+ const float originPositionRight = position->x - glyphInfo->xBearing + glyphInfo->advance;
+ if(originPositionRight > right)
+ {
+ right = originPositionRight;
+ }
}
prevBackgroundColorIndex = backgroundColorIndex;
PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
{
+ Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+ PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+ return pixelData;
+}
+
+PixelData Typesetter::RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer mask, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, float originAlpha)
+{
+ Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+ SetMaskForImageBuffer(mask, result, size.width, size.height, originAlpha);
+
+ PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+ return pixelData;
+}
+
+Devel::PixelBuffer Typesetter::RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
+{
DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER");
// @todo. This initial implementation for a TextLabel has only one visible page.
// Retrieves the layout size.
const Size& layoutSize = mModel->GetLayoutSize();
-
const int32_t outlineWidth = static_cast<int32_t>(mModel->GetOutlineWidth());
// Set the offset for the horizontal alignment according to the text direction and outline width.
int32_t penX = 0;
-
switch(mModel->GetHorizontalAlignment())
{
case HorizontalAlignment::BEGIN:
// Set the offset for the vertical alignment.
int32_t penY = 0u;
-
switch(mModel->GetVerticalAlignment())
{
case VerticalAlignment::TOP:
}
case VerticalAlignment::CENTER:
{
- penY = static_cast<int32_t>(0.5f * (size.height - layoutSize.height));
+ penY = static_cast<int32_t>(std::round(0.5f * (size.height - layoutSize.height)));
penY = penY < 0.f ? 0.f : penY;
+
break;
}
case VerticalAlignment::BOTTOM:
// Create the image buffer for outline
Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
+ const float& blurRadius = mModel->GetOutlineBlurRadius();
+
+ if(blurRadius > Math::MACHINE_EPSILON_1)
+ {
+ outlineImageBuffer.ApplyGaussianBlur(blurRadius);
+ }
+
// Combine the two buffers
CombineImageBuffer(imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight, true);
}
CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
}
+ // Generate the background_with_mask if enabled
+ const bool backgroundWithCutoutEnabled = mModel->IsBackgroundWithCutoutEnabled();
+ if((backgroundWithCutoutEnabled) && RENDER_OVERLAY_STYLE != behaviour)
+ {
+ Devel::PixelBuffer backgroundImageBuffer;
+
+ backgroundImageBuffer = CreateFullBackgroundBuffer(bufferWidth, bufferHeight, mModel->GetBackgroundColorWithCutout());
+
+ // Combine the two buffers
+ CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
+ }
+
if(RENDER_OVERLAY_STYLE == behaviour)
{
if(mModel->IsUnderlineEnabled())
}
}
- // Create the final PixelData for the combined image buffer
- PixelData pixelData = Devel::PixelBuffer::Convert(imageBuffer);
+ return imageBuffer;
+}
+
+Devel::PixelBuffer Typesetter::CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor)
+{
+ const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+ uint8_t backgroundColorAlpha = static_cast<uint8_t>(backgroundColor.a * 255.f);
+
+ Devel::PixelBuffer buffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
- return pixelData;
+ uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(buffer.GetBuffer());
+
+ uint32_t packedBackgroundColor = 0u;
+ uint8_t* packedBackgroundColorBuffer = reinterpret_cast<uint8_t*>(&packedBackgroundColor);
+
+ // Write the color to the pixel buffer
+ *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha;
+ *(packedBackgroundColorBuffer + 2u) = static_cast<uint8_t>(backgroundColor.b * backgroundColorAlpha);
+ *(packedBackgroundColorBuffer + 1u) = static_cast<uint8_t>(backgroundColor.g * backgroundColorAlpha);
+ *(packedBackgroundColorBuffer) = static_cast<uint8_t>(backgroundColor.r * backgroundColorAlpha);
+
+ std::fill(bitmapBuffer, bitmapBuffer + bufferSizeInt, packedBackgroundColor);
+
+ return buffer;
}
Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Typesetter::Style style, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset, const GlyphIndex fromGlyphIndex, const GlyphIndex toGlyphIndex)
const GlyphInfo* __restrict__ hyphens = mModel->GetHyphens();
const Length* __restrict__ hyphenIndices = mModel->GetHyphenIndices();
const Length hyphensCount = mModel->GetHyphensCount();
+ const bool removeFrontInset = mModel->IsRemoveFrontInset();
+ const bool removeBackInset = mModel->IsRemoveBackInset();
+ const bool cutoutEnabled = mModel->IsCutoutEnabled();
// Elided text info. Indices according to elided text and Ellipsis position.
const auto startIndexOfGlyphs = mModel->GetStartIndexOfElidedGlyphs();
if(style == Typesetter::STYLE_OUTLINE)
{
+ const Vector2& outlineOffset = mModel->GetOutlineOffset();
+
glyphData.horizontalOffset -= outlineWidth;
+ glyphData.horizontalOffset += outlineOffset.x;
if(lineIndex == 0u)
{
// Only need to add the vertical outline offset for the first line
glyphData.verticalOffset -= outlineWidth;
+ glyphData.verticalOffset += outlineOffset.y;
}
}
else if(style == Typesetter::STYLE_SHADOW)
}
// Calculate the positions of leftmost and rightmost glyphs in the current line
- if(position.x < lineExtentLeft)
+ if(removeFrontInset)
{
- lineExtentLeft = position.x;
+ if(position.x < lineExtentLeft)
+ {
+ lineExtentLeft = position.x;
+ }
+ }
+ else
+ {
+ const float originPositionLeft = position.x - glyphInfo->xBearing;
+ if(originPositionLeft < lineExtentLeft)
+ {
+ lineExtentLeft = originPositionLeft;
+ }
}
- if(position.x + glyphInfo->width > lineExtentRight)
+ if(removeBackInset)
{
- lineExtentRight = position.x + glyphInfo->width;
+ if(position.x + glyphInfo->width > lineExtentRight)
+ {
+ lineExtentRight = position.x + glyphInfo->width;
+ }
+ }
+ else
+ {
+ const float originPositionRight = position.x - glyphInfo->xBearing + glyphInfo->advance;
+ if(originPositionRight > lineExtentRight)
+ {
+ lineExtentRight = originPositionRight;
+ }
}
// Retrieves the glyph's color.
color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u));
}
+ if(style == Typesetter::STYLE_NONE && cutoutEnabled)
+ {
+ // Temporarily adjust the transparency to 1.f
+ color.a = 1.f;
+ }
+
// Premultiply alpha
color.r *= color.a;
color.g *= color.a;
return topPixelBuffer;
}
+void Typesetter::SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha)
+{
+ // Assume that we always combine two RGBA images
+ // Jump with 4bytes for optimize runtime.
+ uint32_t* topBuffer = reinterpret_cast<uint32_t*>(topPixelBuffer.GetBuffer());
+ uint32_t* bottomBuffer = reinterpret_cast<uint32_t*>(bottomPixelBuffer.GetBuffer());
+
+ if(topBuffer == NULL || bottomBuffer == NULL)
+ {
+ // Nothing to do if one of both buffers are empty.
+ return;
+ }
+
+ const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+
+ for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
+ {
+ uint32_t topBufferColor = *(topBuffer);
+ uint32_t bottomBufferColor = *(bottomBuffer);
+ uint8_t* __restrict__ topBufferColorBuffer = reinterpret_cast<uint8_t*>(&topBufferColor);
+ uint8_t* __restrict__ bottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&bottomBufferColor);
+
+ uint8_t topAlpha = topBufferColorBuffer[3];
+ uint8_t bottomAlpha = 255 - topAlpha;
+
+ float tempTop[4], tempBottom[4];
+
+ // Return the transparency of the text to original.
+ tempTop[0] = static_cast<float>(topBufferColorBuffer[0]) * originAlpha;
+ tempTop[1] = static_cast<float>(topBufferColorBuffer[1]) * originAlpha;
+ tempTop[2] = static_cast<float>(topBufferColorBuffer[2]) * originAlpha;
+ tempTop[3] = static_cast<float>(topBufferColorBuffer[3]) * originAlpha;
+
+ // Manual blending.
+ tempBottom[0] = static_cast<float>(bottomBufferColorBuffer[0]) * static_cast<float>(bottomAlpha) / 255.f;
+ tempBottom[1] = static_cast<float>(bottomBufferColorBuffer[1]) * static_cast<float>(bottomAlpha) / 255.f;
+ tempBottom[2] = static_cast<float>(bottomBufferColorBuffer[2]) * static_cast<float>(bottomAlpha) / 255.f;
+ tempBottom[3] = static_cast<float>(bottomBufferColorBuffer[3]) * static_cast<float>(bottomAlpha) / 255.f;
+
+ bottomBufferColorBuffer[0] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[0] + tempTop[0])));
+ bottomBufferColorBuffer[1] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[1] + tempTop[1])));
+ bottomBufferColorBuffer[2] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[2] + tempTop[2])));
+ bottomBufferColorBuffer[3] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[3] + tempTop[3])));
+
+ *(bottomBuffer) = bottomBufferColor;
+
+ // Increase each buffer's pointer.
+ ++topBuffer;
+ ++bottomBuffer;
+ }
+}
+
Typesetter::Typesetter(const ModelInterface* const model)
: mModel(new ViewModel(model))
{
*/
PixelData Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888);
+ /**
+ * @brief After the Render, use the pixel information of the given cutoutBuffer to make the part where the pixel is drawn transparent.
+ *
+ * @param[in] size The renderer size.
+ * @param[in] textDirection The direction of the text.
+ * @param[in] cutoutBuffer The buffer to use pixel information to cutout.
+ * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+ * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+ * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+ * @param[in] originAlpha The original alpha of text.
+ *
+ * @return A pixel data with the text rendered.
+ */
+ PixelData RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer cutoutBuffer, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888, float originAlpha = 1.f);
+
+ /**
+ * @brief Renders the text, return as Devel::PixelBuffer.
+ *
+ * This function is used to obtain the PixelBuffer required for cutout.
+ *
+ * @param[in] size The renderer size.
+ * @param[in] textDirection The direction of the text.
+ * @param[in] cutoutBuffer The buffer to use pixel information to cutout.
+ * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+ * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+ * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+ *
+ * @return A pixel data with the text rendered.
+ */
+ Devel::PixelBuffer RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888);
+
+ /**
+ * @brief Create & draw the image buffer of single background color.
+ *
+ * @param[in] bufferWidth The width of the image buffer.
+ * @param[in] bufferHeight The height of the image buffer.
+ * @param[in] backgroundColor The backgroundColor of image buffer.
+ *
+ * @return An image buffer with the text.
+ */
+ Devel::PixelBuffer CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor);
+
+ /**
+ * @brief Set Mask for two pixel buffer.
+ *
+ * The alpha value of bottomPixelBuffer is decreased as the alpha value of topPixelBuffer is higher.
+ *
+ * @param[in, out] topPixelBuffer The top layer buffer.
+ * @param[in, out] bottomPixelBuffer The bottom layer buffer.
+ * @param[in] bufferWidth The width of the image buffer.
+ * @param[in] bufferHeight The height of the image buffer.
+ * @param[in] originAlpha The original alpha value of the text.
+ */
+ void SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha);
+
private:
/**
* @brief Private constructor.
mModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
}
+const Vector2& ViewModel::GetOutlineOffset() const
+{
+ return mModel->GetOutlineOffset();
+}
+
const Vector4& ViewModel::GetOutlineColor() const
{
return mModel->GetOutlineColor();
return mModel->GetOutlineWidth();
}
+const float& ViewModel::GetOutlineBlurRadius() const
+{
+ return mModel->GetOutlineBlurRadius();
+}
+
const Vector4& ViewModel::GetBackgroundColor() const
{
return mModel->GetBackgroundColor();
return mModel->GetFontDescriptionRuns();
}
+bool ViewModel::IsRemoveFrontInset() const
+{
+ return mModel->IsRemoveFrontInset();
+}
+
+bool ViewModel::IsRemoveBackInset() const
+{
+ return mModel->IsRemoveBackInset();
+}
+
+bool ViewModel::IsCutoutEnabled() const
+{
+ return mModel->IsCutoutEnabled();
+}
+
+const bool ViewModel::IsBackgroundWithCutoutEnabled() const
+{
+ return mModel->IsBackgroundWithCutoutEnabled();
+}
+
+const Vector4& ViewModel::GetBackgroundColorWithCutout() const
+{
+ return mModel->GetBackgroundColorWithCutout();
+}
+
} // namespace Text
} // namespace Toolkit
void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
/**
+ * @copydoc ModelInterface::GetOutlineOffset()
+ */
+ const Vector2& GetOutlineOffset() const override;
+
+ /**
* @copydoc ModelInterface::GetOutlineColor()
*/
const Vector4& GetOutlineColor() const override;
uint16_t GetOutlineWidth() const override;
/**
+ * @copydoc ModelInterface::GetOutlineBlurRadius()
+ */
+ const float& GetOutlineBlurRadius() const override;
+
+ /**
* @copydoc ModelInterface::GetBackgroundColor()
*/
const Vector4& GetBackgroundColor() const override;
*/
const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const override;
+ /**
+ * @copydoc ModelInterface::IsRemoveFrontInset()
+ */
+ bool IsRemoveFrontInset() const override;
+
+ /**
+ * @copydoc ModelInterface::IsRemoveBackInset()
+ */
+ bool IsRemoveBackInset() const override;
+
+ /**
+ * @copydoc ModelInterface::IsCutoutEnabled()
+ */
+ bool IsCutoutEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled()
+ */
+ const bool IsBackgroundWithCutoutEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::GetBackgroundColorWithCutout()
+ */
+ const Vector4& GetBackgroundColorWithCutout() const override;
+
private:
const ModelInterface* const mModel; ///< Pointer to the text's model.
Vector<GlyphInfo> mElidedGlyphs; ///< Stores the glyphs of the elided text.
#define DALI_TOOLKIT_INTERNAL_TEXT_SPANS_CONTAINER_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow SpanRangesContainer to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::SpanRangesContainer> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::SpanRangesContainer>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANS_CONTAINER_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow Spannable to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Spannable> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Spannable>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_STRING_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow SpannableString to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::SpannableString> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::SpannableString>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_STRING_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_SPANNED_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow Spanned to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Spanned> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Spanned>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNED_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_BASE_SPAN_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow BaseSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::BaseSpan> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::BaseSpan>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_BASE_SPAN_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_CHARACTER_SEQUENCE_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow AbstractStyleSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::CharacterSequence> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::CharacterSequence>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_CHARACTER_SEQUENCE_IMPL_H
#define DALI_TOOLKIT_INTERNAL_TEXT_RANGE_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
} // namespace Toolkit
-// Allow Range to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Range> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Range>
-{
- enum
- {
- IS_TRIVIAL_TYPE = true
- };
-};
-
} // namespace Dali
#endif // DALI_TOOLKIT_INTERNAL_TEXT_RANGE_IMPL_H
bool& colorDefined,
Vector4& color,
bool& widthDefined,
- uint16_t& width)
+ uint16_t& width,
+ bool& offsetDefined,
+ Vector2& offset,
+ bool& blurRadiusDefined,
+ float& blurRadius)
{
const unsigned int numberOfItems = underlinePropertiesMap.Count();
widthDefined = true;
width = static_cast<uint16_t>(valueGet.second.Get<float>());
}
+ else if((DevelText::Outline::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
+ {
+ /// Offset key.
+ offsetDefined = true;
+
+ if(valueGet.second.GetType() == Dali::Property::STRING)
+ {
+ const std::string offsetStr = valueGet.second.Get<std::string>();
+ StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
+ }
+ else
+ {
+ offset = valueGet.second.Get<Vector2>();
+ }
+ }
+ else if((DevelText::Outline::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
+ {
+ /// Blur radius key.
+ blurRadiusDefined = true;
+
+ if(valueGet.second.GetType() == Dali::Property::STRING)
+ {
+ const std::string blurRadiusStr = valueGet.second.Get<std::string>();
+ blurRadius = StringToFloat(blurRadiusStr.c_str());
+ }
+ else
+ {
+ blurRadius = valueGet.second.Get<float>();
+ }
+ }
}
return 0u == numberOfItems;
{
const Property::Map& propertiesMap = value.Get<Property::Map>();
- bool colorDefined = false;
+ bool colorDefined = false;
Vector4 color;
- bool widthDefined = false;
- uint16_t width = 0u;
+ bool widthDefined = false;
+ uint16_t width = 0u;
+ bool offsetDefined = false;
+ Vector2 offset;
+ bool blurRadiusDefined = false;
+ float blurRadius;
bool empty = true;
colorDefined,
color,
widthDefined,
- width);
+ width,
+ offsetDefined,
+ offset,
+ blurRadiusDefined,
+ blurRadius);
controller->OutlineSetByString(false);
}
controller->SetOutlineWidth(width);
update = true;
}
+
+ if(offsetDefined && (controller->GetOutlineOffset() != offset))
+ {
+ controller->SetOutlineOffset(offset);
+ update = true;
+ }
+
+ if(blurRadiusDefined && (!Dali::Equals(controller->GetOutlineBlurRadius(), blurRadius)))
+ {
+ controller->SetOutlineBlurRadius(blurRadius);
+ update = true;
+ }
}
else
{
}
else
{
- const Vector4& color = controller->GetOutlineColor();
- const uint16_t width = controller->GetOutlineWidth();
+ const Vector4& color = controller->GetOutlineColor();
+ const uint16_t width = controller->GetOutlineWidth();
+ const Vector2& offset = controller->GetOutlineOffset();
+ const float& blurRadius = controller->GetOutlineBlurRadius();
Property::Map map;
map.Insert(COLOR_KEY, color);
map.Insert(WIDTH_KEY, static_cast<int>(width));
+ map.Insert(OFFSET_KEY, offset);
+ map.Insert(BLUR_RADIUS_KEY, blurRadius);
value = map;
virtual void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const = 0;
/**
+ * @brief Retrieves the outline offset.
+ *
+ * @return The outline offset.
+ */
+ virtual const Vector2& GetOutlineOffset() const = 0;
+
+ /**
* @brief Retrieve the outline color.
*
* @return The outline color.
virtual uint16_t GetOutlineWidth() const = 0;
/**
+ * @brief Retrieve the outline blur radius.
+ *
+ * @return The outline blur radius.
+ */
+ virtual const float& GetOutlineBlurRadius() const = 0;
+
+ /**
* @brief Retrieves the background color.
*
* @return The background color.
* @return The reference for font description runs.
*/
virtual const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const = 0;
+
+ /**
+ * @brief Retrieves the remove front inset is enabled or not.
+ *
+ * @return boolean if it is enabled.
+ */
+ virtual bool IsRemoveFrontInset() const = 0;
+
+ /**
+ * @brief Retrieves the remove back inset is enabled or not.
+ *
+ * @return boolean if it is enabled.
+ */
+ virtual bool IsRemoveBackInset() const = 0;
+
+ /**
+ * @brief Retrieves the cutout is enabled or not.
+ *
+ * @return boolean if it is enabled.
+ */
+ virtual bool IsCutoutEnabled() const = 0;
+
+ /**
+ * @brief Retrieves the background with cutout is enabled or not.
+ *
+ * @return boolean if it is enabled.
+ */
+ virtual const bool IsBackgroundWithCutoutEnabled() const = 0;
+
+ /**
+ * @brief Retrieves the color of the background with cutout.
+ *
+ * @return The color of the background with cutout.
+ */
+ virtual const Vector4& GetBackgroundColorWithCutout() const = 0;
};
} // namespace Text
mVisualModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
}
+const Vector2& Model::GetOutlineOffset() const
+{
+ return mVisualModel->GetOutlineOffset();
+}
+
const Vector4& Model::GetOutlineColor() const
{
return mVisualModel->GetOutlineColor();
return mVisualModel->GetOutlineWidth();
}
+const float& Model::GetOutlineBlurRadius() const
+{
+ return mVisualModel->mOutlineBlurRadius;
+}
+
const Vector4& Model::GetBackgroundColor() const
{
return mVisualModel->GetBackgroundColor();
return mLogicalModel->mFontDescriptionRuns;
}
+bool Model::IsRemoveFrontInset() const
+{
+ return mRemoveFrontInset;
+}
+
+bool Model::IsRemoveBackInset() const
+{
+ return mRemoveBackInset;
+}
+
+bool Model::IsCutoutEnabled() const
+{
+ return mVisualModel->IsCutoutEnabled();
+}
+
+const bool Model::IsBackgroundWithCutoutEnabled() const
+{
+ return mVisualModel->IsBackgroundWithCutoutEnabled();
+}
+
+const Vector4& Model::GetBackgroundColorWithCutout() const
+{
+ return mVisualModel->GetBackgroundColorWithCutout();
+}
+
Model::Model()
: mLogicalModel(),
mVisualModel(),
void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
/**
+ * @copydoc ModelInterface::GetOutlineOffset()
+ */
+ const Vector2& GetOutlineOffset() const override;
+
+ /**
* @copydoc ModelInterface::GetOutlineColor()
*/
const Vector4& GetOutlineColor() const override;
uint16_t GetOutlineWidth() const override;
/**
+ * @copydoc ModelInterface::GetOutlineBlurRadius()
+ */
+ const float& GetOutlineBlurRadius() const override;
+
+ /**
* @copydoc ModelInterface::GetBackgroundColor()
*/
const Vector4& GetBackgroundColor() const override;
*/
const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const override;
+ /**
+ * @copydoc ModelInterface::IsRemoveFrontInset()
+ */
+ bool IsRemoveFrontInset() const override;
+
+ /**
+ * @copydoc ModelInterface::IsRemoveBackInset()
+ */
+ bool IsRemoveBackInset() const override;
+
+ /**
+ * @copydoc ModelInterface::IsCutoutEnabled()
+ */
+ bool IsCutoutEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled()
+ */
+ const bool IsBackgroundWithCutoutEnabled() const override;
+
+ /**
+ * @copydoc ModelInterface::GetBackgroundColorWithCutout()
+ */
+ const Vector4& GetBackgroundColorWithCutout() const override;
+
private: // Private contructors & copy operator.
/**
* @brief Private constructor.
void TextScroller::StopScrolling()
{
- if(mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING)
+ if(IsScrolling())
{
switch(mStopMode)
{
case TextLabel::AutoScrollStopMode::IMMEDIATE:
{
+ mIsStop = true;
mScrollAnimation.Stop();
- mScrollerInterface.ScrollingFinished();
break;
}
case TextLabel::AutoScrollStopMode::FINISH_LOOP:
{
+ mIsStop = true;
mScrollAnimation.SetLoopCount(1); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
break;
}
}
}
+bool TextScroller::IsStop()
+{
+ return mIsStop;
+}
+
+bool TextScroller::IsScrolling()
+{
+ return (mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING);
+}
+
TextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
{
return mStopMode;
mLoopCount(1),
mLoopDelay(0.0f),
mWrapGap(0.0f),
- mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP)
+ mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP),
+ mIsStop(false)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n");
}
void TextScroller::SetParameters(Actor scrollingTextActor, Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textureSize, const float wrapGap, CharacterDirection direction, HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] textureSize[%f,%f] direction[%d]\n", controlSize.x, controlSize.y, textureSize.x, textureSize.y, direction);
-
mRenderer = renderer;
float animationProgress = 0.0f;
if(mLoopCount > 0) // If not a ininity loop, then calculate remained loop
{
remainedLoop = mLoopCount - (mScrollAnimation.GetCurrentLoop());
- remainedLoop = (remainedLoop <= 0 ? 1 : remainedLoop);
+ remainedLoop = mIsStop ? 1 : (remainedLoop <= 0 ? 1 : remainedLoop);
}
}
mScrollAnimation.Clear();
void TextScroller::AutoScrollAnimationFinished(Dali::Animation& animation)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n");
+ mIsStop = false;
mScrollerInterface.ScrollingFinished();
// Revert to the original shader and texture after scrolling
void TextScroller::StartScrolling(Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed);
-
Shader shader = mRenderer.GetShader();
mScrollAnimation = Animation::New(scrollDuration);
mScrollAnimation.AnimateTo(Property(shader, mScrollDeltaIndex), scrollAmount, TimePeriod(mLoopDelay, scrollDuration));
mScrollAnimation.SetLoopCount(loopCount);
mScrollAnimation.FinishedSignal().Connect(this, &TextScroller::AutoScrollAnimationFinished);
mScrollAnimation.Play();
+
+ mIsStop = false;
}
} // namespace Text
void StopScrolling();
/**
+ * @brief Whether the stop scrolling has been triggered or not.
+ */
+ bool IsStop();
+
+ /**
+ * @brief Whether the scroll animation is playing or not.
+ */
+ bool IsScrolling();
+
+ /**
* @brief Get the mode of scrolling stop
* @return stopMode type when text scrolling is stoped.
*/
float mLoopDelay; ///< Time delay of loop start
float mWrapGap; ///< Gap before text wraps around when scrolling
TextLabel::AutoScrollStopMode::Type mStopMode; ///< Stop mode of scrolling text, when loop count is 0.
+ bool mIsStop : 1; ///< Whether the stop scrolling has been triggered or not.
}; // TextScroller class
Length numberOfRuns) const = 0;
/**
+ * @brief Retrieves the outline offset.
+ *
+ * @return The outline offset.
+ */
+ virtual const Vector2& GetOutlineOffset() const = 0;
+
+ /**
* @brief Retrieve the outline color.
*
* @return The outline color.
* @return GetGlyphsToCharacters.
*/
virtual const Vector<CharacterIndex>& GetGlyphsToCharacters() const = 0;
+
+ /**
+ * @brief Returns whether cutout is enabled or not.
+ *
+ * @return The cutout state.
+ */
+ virtual bool IsCutoutEnabled() const = 0;
};
} // namespace Text
}
}
+const Vector2& View::GetOutlineOffset() const
+{
+// TODO : We should support outline offset to editable text.
+/*
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->GetOutlineOffset();
+ }
+*/
+ return Vector2::ZERO;
+}
+
const Vector4& View::GetOutlineColor() const
{
if(mImpl->mVisualModel)
return mImpl->mVisualModel->GetGlyphsToCharacters();
}
+bool View::IsCutoutEnabled() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->IsCutoutEnabled();
+ }
+ return false;
+}
+
} // namespace Dali::Toolkit::Text
Length numberOfRuns) const;
/**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineOffset()
+ */
+ const Vector2& GetOutlineOffset() const override;
+
+ /**
* @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineColor()
*/
const Vector4& GetOutlineColor() const override;
*/
const Vector<CharacterIndex>& GetGlyphsToCharacters() const override;
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::IsCutoutEnabled()
+ */
+ bool IsCutoutEnabled() const override;
+
private:
// Undefined
View(const View& handle);
mUnderlineColorSet = true;
}
+void VisualModel::SetOutlineOffset(const Vector2& outlineOffset)
+{
+ mOutlineOffset = outlineOffset;
+}
+
void VisualModel::SetOutlineColor(const Vector4& color)
{
mOutlineColor = color;
}
+void VisualModel::SetOutlineBlurRadius(const float& outlineBlurRadius)
+{
+ mOutlineBlurRadius = outlineBlurRadius;
+}
+
void VisualModel::SetUnderlineEnabled(bool enabled)
{
mUnderlineEnabled = enabled;
return mUnderlineColor;
}
+const Vector2& VisualModel::GetOutlineOffset() const
+{
+ return mOutlineOffset;
+}
+
const Vector4& VisualModel::GetOutlineColor() const
{
return mOutlineColor;
}
+const float& VisualModel::GetOutlineBlurRadius() const
+{
+ return mOutlineBlurRadius;
+}
+
bool VisualModel::IsUnderlineEnabled() const
{
return mUnderlineEnabled;
return mGlyphsToCharacters;
}
+void VisualModel::SetCutoutEnabled(bool enable)
+{
+ mCutoutEnabled = enable;
+}
+
+bool VisualModel::IsCutoutEnabled() const
+{
+ return mCutoutEnabled;
+}
+
+void VisualModel::SetBackgroundWithCutoutEnabled(bool enable)
+{
+ mBackgroundWithCutoutEnabled = enable;
+}
+
+bool VisualModel::IsBackgroundWithCutoutEnabled() const
+{
+ return mBackgroundWithCutoutEnabled;
+}
+
+void VisualModel::SetBackgroundColorWithCutout(const Vector4& color)
+{
+ mBackgroundColorWithCutout = color;
+}
+
+const Vector4& VisualModel::GetBackgroundColorWithCutout() const
+{
+ return mBackgroundColorWithCutout;
+}
+
VisualModel::~VisualModel()
{
}
mStrikethroughColor(Color::BLACK),
mControlSize(),
mShadowOffset(),
+ mOutlineOffset(),
mUnderlineHeight(0.0f),
mStrikethroughHeight(0.0f),
mUnderlineType(Text::Underline::SOLID),
mDashedUnderlineWidth(2.0f),
mDashedUnderlineGap(1.0f),
mShadowBlurRadius(0.0f),
+ mOutlineBlurRadius(0.0f),
mOutlineWidth(0u),
mNaturalSize(),
mLayoutSize(),
mBackgroundEnabled(false),
mMarkupProcessorEnabled(false),
mStrikethroughEnabled(false),
- mCharacterSpacing(0.0f)
-
+ mCharacterSpacing(0.0f),
+ mCutoutEnabled(false),
+ mBackgroundWithCutoutEnabled(false)
{
}
Length GetNumberOfUnderlineRuns() const;
/**
+ * @brief Sets the text's outline offset.
+ *
+ * @param[in] outlineOffset The outline offset.
+ */
+ void SetOutlineOffset(const Vector2& outlineOffset);
+
+ /**
* @brief Set the outline color.
*
* @param[in] color color of outline.
void SetOutlineColor(const Vector4& color);
/**
+ * @brief Retrieves the text's outline offset.
+ *
+ * @return The text's outline offset.
+ */
+ const Vector2& GetOutlineOffset() const;
+
+ /**
* @brief Retrieve the outline color.
*
* @return The outline color.
uint16_t GetOutlineWidth() const;
/**
+ * @brief Set the outline blur radius.
+ *
+ * @param[in] outlineBlurRadius The outline blur radius, 0,0 indicates no blur.
+ */
+ void SetOutlineBlurRadius(const float& outlineBlurRadius);
+
+ /**
+ * @brief Retrieve the outline blur radius.
+ *
+ * @return The outline blur radius.
+ */
+ const float& GetOutlineBlurRadius() const;
+
+ /**
* @brief Sets the text's background color.
*
* @param[in] color The text's background color.
*/
const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const;
+ /**
+ * @brief Sets the cutout flag.
+ *
+ * @param[in] enable true if cutouted.
+ */
+ void SetCutoutEnabled(bool enable);
+
+ /**
+ * @brief Returns whether the text is cutouted or not.
+ *
+ * @return cutout state.
+ */
+ bool IsCutoutEnabled() const;
+
+ /**
+ * @brief Sets the background with cutout flag.
+ *
+ * @param[in] enable true if background enabled.
+ */
+ void SetBackgroundWithCutoutEnabled(bool enable);
+
+ /**
+ * @brief Returns whether the text is cutouted or not.
+ *
+ * @return True if enabled.
+ */
+ bool IsBackgroundWithCutoutEnabled() const;
+
+ /**
+ * @brief Sets the Color of background with cutout.
+ *
+ * @param[in] color The color to set.
+ */
+ void SetBackgroundColorWithCutout(const Vector4& color);
+
+ /**
+ * @brief Retrieves the Color of background with cutout.
+ *
+ * @return The color.
+ */
+ const Vector4& GetBackgroundColorWithCutout() const;
+
protected:
/**
* @brief A reference counted object may only be deleted by calling Unreference().
VisualModel& operator=(const VisualModel& handle);
public:
- Vector<GlyphInfo> mGlyphs; ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
- Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
- Vector<GlyphIndex> mCharactersToGlyph; ///< For each character, the index of the first glyph.
- Vector<Length> mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
- Vector<Length> mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
- Vector<Vector2> mGlyphPositions; ///< For each glyph, the position.
- Vector<LineRun> mLines; ///< The laid out lines.
- Vector<UnderlinedGlyphRun> mUnderlineRuns; ///< Runs of glyphs that are underlined.
- Vector<Vector4> mColors; ///< Colors of the glyphs.
- Vector<ColorIndex> mColorIndices; ///< Indices to the vector of colors for each glyphs.
- Vector<Vector4> mBackgroundColors; ///< Background colors of the glyphs.
- Vector<ColorIndex> mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
- Vector4 mTextColor; ///< The text color
- Vector4 mShadowColor; ///< Color of drop shadow
- Vector4 mUnderlineColor; ///< Color of underline
- Vector4 mOutlineColor; ///< Color of outline
- Vector4 mBackgroundColor; ///< Color of text background
- Vector4 mStrikethroughColor; ///< Color of text background
- Size mControlSize; ///< The size of the UI control.
- Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow
- float mUnderlineHeight; ///< Fixed height for underline to override font metrics.
- float mStrikethroughHeight; ///< Fixed height for strikethrough to override font metrics.
- Text::Underline::Type mUnderlineType; ///< The type of the underline.
- float mDashedUnderlineWidth; ///< The width of the dashes of the dashed underline.
- float mDashedUnderlineGap; ///< The gap between the dashes of the dashed underline.
- float mShadowBlurRadius; ///< Blur radius of shadow, 0 indicates no blur.
- uint16_t mOutlineWidth; ///< Width of outline.
- Vector<StrikethroughGlyphRun> mStrikethroughRuns; ///< Runs of glyphs that have strikethrough.
- Vector<CharacterSpacingGlyphRun> mCharacterSpacingRuns; ///< Runs of glyphs that have character-spacing.
+ Vector<GlyphInfo> mGlyphs; ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+ Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
+ Vector<GlyphIndex> mCharactersToGlyph; ///< For each character, the index of the first glyph.
+ Vector<Length> mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
+ Vector<Length> mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
+ Vector<Vector2> mGlyphPositions; ///< For each glyph, the position.
+ Vector<LineRun> mLines; ///< The laid out lines.
+ Vector<UnderlinedGlyphRun> mUnderlineRuns; ///< Runs of glyphs that are underlined.
+ Vector<Vector4> mColors; ///< Colors of the glyphs.
+ Vector<ColorIndex> mColorIndices; ///< Indices to the vector of colors for each glyphs.
+ Vector<Vector4> mBackgroundColors; ///< Background colors of the glyphs.
+ Vector<ColorIndex> mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
+ Vector4 mTextColor; ///< The text color
+ Vector4 mShadowColor; ///< Color of drop shadow
+ Vector4 mUnderlineColor; ///< Color of underline
+ Vector4 mOutlineColor; ///< Color of outline
+ Vector4 mBackgroundColor; ///< Color of text background
+ Vector4 mStrikethroughColor; ///< Color of text background
+ Size mControlSize; ///< The size of the UI control.
+ Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow
+ Vector2 mOutlineOffset; ///< Offset for outline
+ float mUnderlineHeight; ///< Fixed height for underline to override font metrics.
+ float mStrikethroughHeight; ///< Fixed height for strikethrough to override font metrics.
+ Text::Underline::Type mUnderlineType; ///< The type of the underline.
+ float mDashedUnderlineWidth; ///< The width of the dashes of the dashed underline.
+ float mDashedUnderlineGap; ///< The gap between the dashes of the dashed underline.
+ float mShadowBlurRadius; ///< Blur radius of shadow, 0 indicates no blur.
+ float mOutlineBlurRadius; ///< Blur radius of outline, 0 indicates no blur.
+ uint16_t mOutlineWidth; ///< Width of outline.
+ Vector<StrikethroughGlyphRun> mStrikethroughRuns; ///< Runs of glyphs that have strikethrough.
+ Vector<CharacterSpacingGlyphRun> mCharacterSpacingRuns; ///< Runs of glyphs that have character-spacing.
+ Vector4 mBackgroundColorWithCutout; ///< Background color with cutout.
private:
Size mNaturalSize; ///< Size of the text with no line wrapping.
bool mTextElideEnabled : 1; ///< Whether the text's elide is enabled.
public:
- bool mUnderlineEnabled : 1; ///< Underline enabled flag
- bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
- bool mBackgroundEnabled : 1; ///< Background enabled flag
- bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
- HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
- bool mStrikethroughEnabled : 1; ///< Strikethrough enabled flag
- float mCharacterSpacing; ///< Contains the value of the character spacing.
+ bool mUnderlineEnabled : 1; ///< Underline enabled flag
+ bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
+ bool mBackgroundEnabled : 1; ///< Background enabled flag
+ bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
+ HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
+ bool mStrikethroughEnabled : 1; ///< Strikethrough enabled flag
+ float mCharacterSpacing; ///< Contains the value of the character spacing.
+ bool mCutoutEnabled : 1; ///< Cutout enabled flag
+ bool mBackgroundWithCutoutEnabled : 1; ///< Background with cutout enabled flag.
};
} // namespace Text
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
TextureManager::TextureManager(bool loadYuvPlanes)
: mTextureCacheManager(),
mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
- mLifecycleObservers(),
mLoadQueue(),
mLoadingQueueTextureId(INVALID_TEXTURE_ID),
mRemoveQueue(),
Adaptor::Get().UnregisterProcessor(*this, true);
mRemoveProcessorRegistered = false;
}
-
- for(auto iter = mLifecycleObservers.Begin(), endIter = mLifecycleObservers.End(); iter != endIter; ++iter)
- {
- (*iter)->TextureManagerDestroyed();
- }
}
TextureSet TextureManager::LoadAnimatedImageTexture(
}
}
-void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer)
-{
- // make sure an observer doesn't observe the same object twice
- // otherwise it will get multiple calls to ObjectDestroyed()
- DALI_ASSERT_DEBUG(mLifecycleObservers.End() == std::find(mLifecycleObservers.Begin(), mLifecycleObservers.End(), &observer));
- mLifecycleObservers.PushBack(&observer);
-}
-
-void TextureManager::RemoveObserver(TextureManager::LifecycleObserver& observer)
-{
- // Find the observer...
- auto endIter = mLifecycleObservers.End();
- for(auto iter = mLifecycleObservers.Begin(); iter != endIter; ++iter)
- {
- if((*iter) == &observer)
- {
- mLifecycleObservers.Erase(iter);
- break;
- }
- }
- DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End());
-}
-
void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
{
switch(textureInfo.loadState)
#define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
using MaskingDataPointer = std::unique_ptr<MaskingData>;
/**
- * Class to provide lifecycle event on destruction of texture manager.
- */
- struct LifecycleObserver
- {
- /**
- * Called shortly before the texture manager is destroyed.
- */
- virtual void TextureManagerDestroyed() = 0;
- };
-
- /**
* Constructor.
*
* @param[in] loadYuvPlanes Whether we allow to load YuvPlanes or not. Default is false.
TextureManager::MultiplyOnLoad& preMultiplyOnLoad);
/**
- * Add an observer to the object.
- * @param[in] observer The observer to add.
- */
- void AddObserver(TextureManager::LifecycleObserver& observer);
-
- /**
- * Remove an observer from the object
- * @pre The observer has already been added.
- * @param[in] observer The observer to remove.
- */
- void RemoveObserver(TextureManager::LifecycleObserver& observer);
-
- /**
* @brief Returns the geometry associated with texture.
* @param[in] textureId Id of the texture
* @param[out] frontElements number of front elements
private: // Member Variables:
TextureCacheManager mTextureCacheManager; ///< Manager the life-cycle and caching of Textures
- std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader; ///< The Asynchronous image loader used to provide all local async loads
- Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
+ std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader; ///< The Asynchronous image loader used to provide all local async loads
Dali::Vector<QueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
TextureManager::TextureId mLoadingQueueTextureId; ///< TextureId when it is loading. it causes Load Textures to be queued.
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/rendering/decorated-visual-renderer.h>
#include <memory>
map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
- map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : mImageCache->GetTotalFrameCount()) : -1);
+
+ // This returns -1 until the loading is finished.
+ int32_t frameCount = mFrameCount;
+ if(mImageCache && frameCount == 0)
+ {
+ frameCount = mImageCache->GetTotalFrameCount();
+
+ if(frameCount <= SINGLE_IMAGE_COUNT && mAnimatedImageLoading && mAnimatedImageLoading.HasLoadingSucceeded())
+ {
+ frameCount = mAnimatedImageLoading.GetImageCount();
+ }
+ else
+ {
+ frameCount = -1;
+ }
+ }
+
+ map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast<int>(frameCount));
map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
mPlacementActor = actor;
PrepareTextureSet();
- DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+ actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
Window window = DevelWindow::Get(actor);
if(window)
{
+ mPlacementWindow = window;
DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
}
}
mCurrentFrameIndex = FIRST_FRAME_INDEX;
mCurrentLoopIndex = FIRST_LOOP;
- DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+ actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
- Window window = DevelWindow::Get(actor);
+ Window window = mPlacementWindow.GetHandle();
if(window)
{
DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
+ mPlacementWindow.Reset();
}
}
}
}
-void AnimatedImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
+void AnimatedImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible)
{
if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
{
mActionStatus = DevelAnimatedImageVisual::Action::STOP;
DisplayNextFrame();
- DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
+ DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this);
}
}
void CheckMaskTexture();
/**
- * @brief Callback when the visibility of the actor is changed.
+ * @brief Callback when the inherited visibility of the actor is changed.
*/
- void OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type);
+ void OnControlInheritedVisibilityChanged(Actor actor, bool visible);
/**
* @brief Callback when the visibility of the window is changed.
private:
Timer mFrameDelayTimer;
+ WeakHandle<Window> mPlacementWindow;
WeakHandle<Actor> mPlacementActor;
ImageVisualShaderFactory& mImageVisualShaderFactory;
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
// EXTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
namespace Dali
TextureSet FixedImageCache::GetTextureSet(uint32_t frameIndex) const
{
TextureSet textureSet = mTextureManager.GetTextureSet(mImageUrls[frameIndex].mTextureId);
- if(textureSet)
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT);
- textureSet.SetSampler(0u, sampler);
- }
return textureSet;
}
void FixedImageCache::ClearCache()
{
- if(mTextureManagerAlive)
+ if(Dali::Adaptor::IsAvailable())
{
for(std::size_t i = 0; i < mImageUrls.size(); ++i)
{
{
if(loadSuccess)
{
- mLoadState = TextureManager::LoadState::LOAD_FINISHED;
+ mLoadState = TextureManager::LoadState::LOAD_FINISHED;
bool isCurrentFrameReady = IsFrameReady(mCurrentFrameIndex);
if(!mRequestingLoad)
{
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
mInterval(interval),
mLoadState(TextureManager::LoadState::NOT_STARTED),
mRequestingLoad(false),
- mPreMultiplyOnLoad(preMultiplyOnLoad),
- mTextureManagerAlive(true)
+ mPreMultiplyOnLoad(preMultiplyOnLoad)
{
- mTextureManager.AddObserver(*this);
}
ImageCache::~ImageCache()
{
- if(mTextureManagerAlive)
- {
- mTextureManager.RemoveObserver(*this);
- }
-}
-
-void ImageCache::TextureManagerDestroyed()
-{
- mTextureManagerAlive = false;
}
void ImageCache::SetInterval(uint32_t interval)
#define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
{
namespace Internal
{
-class ImageCache : public TextureManager::LifecycleObserver
+class ImageCache
{
public:
/**
virtual void SetInterval(uint32_t interval);
private:
- /**
- * @brief Called before the texture manager is destroyed.
- */
- void TextureManagerDestroyed() final;
-
void AllocateMaskData();
protected:
TextureManager::LoadState mLoadState;
bool mRequestingLoad : 1;
bool mPreMultiplyOnLoad : 1;
- bool mTextureManagerAlive : 1;
};
} // namespace Internal
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
// INTERNAL HEADERS
#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
namespace
synchronouslyLoaded = true;
interval = mAnimatedImageLoading.GetFrameInterval(mQueue.Back().mFrameNumber);
}
- MakeFrameReady(synchronouslyLoaded, textureSet, interval, preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+ MakeFrameReady(synchronouslyLoaded, textureSet, mAnimatedImageLoading.GetImageCount(), interval, preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
}
if(popExist || mQueue.IsEmpty() || synchronouslyLoaded)
synchronousLoading,
this,
preMultiplyOnLoading);
- if(textureSet)
+ if(textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode(mWrapModeU, mWrapModeV);
TextureManager::TextureId textureId = GetCachedTextureId(0);
TextureSet textureSet = mTextureManager.GetTextureSet(textureId);
- if(textureSet)
+ if(textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode(mWrapModeU, mWrapModeV);
void RollingAnimatedImageCache::ClearCache()
{
- while(mTextureManagerAlive && !mQueue.IsEmpty())
+ while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty())
{
PopFrontCache();
}
mLoadState = TextureManager::LoadState::NOT_STARTED;
}
-void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval, bool preMultiplied)
+void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t frameCount, uint32_t interval, bool preMultiplied)
{
if(!loadSuccess)
{
mLoadState = TextureManager::LoadState::LOAD_FINISHED;
// Reset size of Queue according to the real frame count.
- if(mFrameCount != mAnimatedImageLoading.GetImageCount())
+ if(mFrameCount != frameCount)
{
- mFrameCount = mAnimatedImageLoading.GetImageCount();
+ mFrameCount = frameCount;
mTextureIds.resize(mFrameCount);
mIntervals.assign(mFrameCount, 0u);
}
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
LOG_CACHE;
- if(textureInformation.textureSet)
+ if(textureInformation.textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode(mWrapModeU, mWrapModeV);
textureInformation.textureSet.SetSampler(0u, sampler);
}
- MakeFrameReady(loadSuccess, textureInformation.textureSet, textureInformation.interval, textureInformation.preMultiplied);
+ MakeFrameReady(loadSuccess, textureInformation.textureSet, textureInformation.frameCount, textureInformation.interval, textureInformation.preMultiplied);
// TODO : We need to remove some below logics, since user can remove Visual during ResourceReady callback.
#define DALI_TOOLKIT_INTERNAL_ROLLING_ANIMATED_IMAGE_CACHE_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*
* @param[in] loadSuccess whether the loading is succeded or not.
* @param[in] textureSet textureSet for this frame.
+ * @param[in] frameCount Total frame count for this image.
* @param[in] interval interval between this frame and next frame.
* @param[in] preMultiplied whether the texture is premultied alpha or not.
*/
- void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval, bool preMultiplied);
+ void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t frameCount, uint32_t interval, bool preMultiplied);
/**
* @brief Pop front entity of Cache.
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
// INTERNAL HEADERS
#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
-#include <dali/integration-api/debug.h>
// EXTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
namespace
{
void RollingImageCache::ClearCache()
{
- while(mTextureManagerAlive && !mQueue.IsEmpty())
+ while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty())
{
PopFrontCache();
}
if(!frontFrameReady && IsFrontReady())
{
- if(textureInformation.textureSet)
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT);
- textureInformation.textureSet.SetSampler(0u, sampler);
- }
mObserver.FrameReady(textureInformation.textureSet, mInterval, textureInformation.preMultiplied);
}
}
#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/devel-api/common/stage.h>
#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/math/math-utils.h>
#include <dali/public-api/rendering/decorated-visual-renderer.h>
mLastSentPlayStateId(0u),
mLoadFailed(false),
mRendererAdded(false),
- mCoreShutdown(false),
mRedrawInScalingDown(true),
mEnableFrameCache(false),
- mUseNativeImage(false)
+ mUseNativeImage(false),
+ mNotifyAfterRasterization(false)
{
// the rasterized image is with pre-multiplied alpha format
mImpl->mFlags |= Visual::Base::Impl::IS_PREMULTIPLIED_ALPHA;
AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
{
- if(!mCoreShutdown)
+ if(Dali::Adaptor::IsAvailable())
{
if(mImageUrl.IsBufferResource())
{
textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
}
- auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
- vectorAnimationManager.RemoveObserver(*this);
-
if(mEventCallback)
{
mFactoryCache.GetVectorAnimationManager().UnregisterEventCallback(mEventCallback);
}
}
-void AnimatedVectorImageVisual::VectorAnimationManagerDestroyed()
-{
- // Core is shutting down. Don't talk to the plugin any more.
- mCoreShutdown = true;
-}
-
void AnimatedVectorImageVisual::GetNaturalSize(Vector2& naturalSize)
{
if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
map.Insert(Toolkit::DevelImageVisual::Property::ENABLE_FRAME_CACHE, mEnableFrameCache);
+ map.Insert(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, mNotifyAfterRasterization);
}
void AnimatedVectorImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
{
DoSetProperty(Toolkit::DevelImageVisual::Property::ENABLE_FRAME_CACHE, keyValue.second);
}
+ else if(keyValue.first == NOTIFY_AFTER_RASTERIZATION)
+ {
+ DoSetProperty(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, keyValue.second);
+ }
}
}
}
break;
}
+
+ case Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION:
+ {
+ bool notifyAfterRasterization = false;
+ if(value.Get(notifyAfterRasterization))
+ {
+ if(mNotifyAfterRasterization != notifyAfterRasterization)
+ {
+ mNotifyAfterRasterization = notifyAfterRasterization;
+
+ mAnimationData.notifyAfterRasterization = mNotifyAfterRasterization;
+ mAnimationData.resendFlag |= VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION;
+ }
+ }
+ break;
+ }
}
}
mVectorAnimationTask->KeepRasterizedBuffer(mEnableFrameCache);
mVectorAnimationTask->RequestLoad(mImageUrl, encodedImageBuffer, IsSynchronousLoadingRequired());
- auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
- vectorAnimationManager.AddObserver(*this);
-
Shader shader = GenerateShader();
Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
mSizeNotification = actor.AddPropertyNotification(Actor::Property::SIZE, StepCondition(3.0f));
mSizeNotification.NotifySignal().Connect(this, &AnimatedVectorImageVisual::OnSizeNotification);
- DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
+ actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged);
Window window = DevelWindow::Get(actor);
if(window)
{
+ mPlacementWindow = window;
DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
}
actor.RemovePropertyNotification(mScaleNotification);
actor.RemovePropertyNotification(mSizeNotification);
- DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
+ actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged);
- Window window = DevelWindow::Get(actor);
+ Window window = mPlacementWindow.GetHandle();
if(window)
{
DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
+ mPlacementWindow.Reset();
}
mPlacementActor.Reset();
}
case DevelAnimatedVectorImageVisual::Action::FLUSH:
{
- if(DALI_LIKELY(!mCoreShutdown))
+ if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
{
SendAnimationData();
}
}
}
- if(mImpl->mRenderer)
+ if(!mNotifyAfterRasterization && mImpl->mRenderer)
{
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
}
}
mVectorAnimationTask->SetAnimationData(mAnimationData);
- if(mImpl->mRenderer)
+ if(mImpl->mRenderer &&
+ ((mAnimationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) ||
+ (mAnimationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)))
{
- if(mAnimationData.playState == DevelImageVisual::PlayState::PLAYING)
+ if(!mNotifyAfterRasterization && mPlayState == DevelImageVisual::PlayState::PLAYING)
{
+ // Make rendering behaviour if we don't notify after rasterization, but animation playing.
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
}
else
{
+ // Otherwise, notify will be sended after rasterization. Make behaviour as required.
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
}
}
void AnimatedVectorImageVisual::TriggerVectorRasterization()
{
- if(!mEventCallback && !mCoreShutdown)
+ if(!mEventCallback && Dali::Adaptor::IsAvailable())
{
mEventCallback = MakeCallback(this, &AnimatedVectorImageVisual::OnProcessEvents);
auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
}
}
-void AnimatedVectorImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
+void AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible)
{
if(!visible)
{
StopAnimation();
TriggerVectorRasterization();
- DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
+ DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this);
}
}
* | url | STRING |
*
*/
-class AnimatedVectorImageVisual : public Visual::Base, public ConnectionTracker, public VectorAnimationManager::LifecycleObserver
+class AnimatedVectorImageVisual : public Visual::Base, public ConnectionTracker
{
public:
/**
*/
void EnablePreMultipliedAlpha(bool preMultiplied) override;
-protected: // From VectorAnimationManager::LifecycleObserver:
- /**
- * @copydoc VectorAnimationManager::LifecycleObserver::VectorAnimationManagerDestroyed()
- */
- void VectorAnimationManagerDestroyed() override;
-
protected:
/**
* @brief Constructor.
/**
* @brief Callback when the visibility of the actor is changed.
*/
- void OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type);
+ void OnControlInheritedVisibilityChanged(Actor actor, bool visible);
/**
* @brief Callback when the visibility of the window is changed.
AnimatedVectorImageVisual& operator=(const AnimatedVectorImageVisual& visual) = delete;
private:
+ WeakHandle<Window> mPlacementWindow;
VisualUrl mImageUrl;
VectorAnimationTask::AnimationData mAnimationData;
VectorAnimationTaskPtr mVectorAnimationTask;
bool mLoadFailed : 1;
bool mRendererAdded : 1;
- bool mCoreShutdown : 1;
bool mRedrawInScalingDown : 1;
bool mEnableFrameCache : 1;
bool mUseNativeImage : 1;
+ bool mNotifyAfterRasterization : 1;
};
} // namespace Internal
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
VectorAnimationManager::VectorAnimationManager()
: mEventCallbacks(),
- mLifecycleObservers(),
mVectorAnimationThread(nullptr),
mProcessorRegistered(false)
{
VectorAnimationManager::~VectorAnimationManager()
{
- mEventCallbacks.clear();
+ mEventCallbacks.Clear();
if(mProcessorRegistered && Adaptor::IsAvailable())
{
Adaptor::Get().UnregisterProcessor(*this, true);
}
-
- for(auto observer : mLifecycleObservers)
- {
- observer->VectorAnimationManagerDestroyed();
- }
-}
-
-void VectorAnimationManager::AddObserver(VectorAnimationManager::LifecycleObserver& observer)
-{
- DALI_ASSERT_DEBUG(mLifecycleObservers.end() == std::find(mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer));
- mLifecycleObservers.push_back(&observer);
-}
-
-void VectorAnimationManager::RemoveObserver(VectorAnimationManager::LifecycleObserver& observer)
-{
- auto iterator = std::find(mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer);
- if(iterator != mLifecycleObservers.end())
- {
- mLifecycleObservers.erase(iterator);
- }
}
VectorAnimationThread& VectorAnimationManager::GetVectorAnimationThread()
void VectorAnimationManager::RegisterEventCallback(CallbackBase* callback)
{
- mEventCallbacks.emplace_back(std::unique_ptr<Dali::CallbackBase>(callback));
+ mEventCallbacks.PushBack(callback); ///< Take ownership of callback.
if(!mProcessorRegistered)
{
void VectorAnimationManager::UnregisterEventCallback(CallbackBase* callback)
{
- auto iter = std::find_if(mEventCallbacks.begin(),
- mEventCallbacks.end(),
- [callback](const std::unique_ptr<CallbackBase>& element) {
- return element.get() == callback;
- });
- if(iter != mEventCallbacks.end())
+ auto iter = mEventCallbacks.Find(callback);
+ if(iter != mEventCallbacks.End())
{
- mEventCallbacks.erase(iter);
+ mEventCallbacks.Erase(iter);
- if(mEventCallbacks.empty())
+ if(mEventCallbacks.Count() == 0u)
{
if(Adaptor::IsAvailable())
{
#ifdef TRACE_ENABLED
if(gTraceFilter && gTraceFilter->IsTraceEnabled())
{
- if(mEventCallbacks.size() > 0u)
+ if(mEventCallbacks.Count() > 0u)
{
std::ostringstream oss;
- oss << "[" << mEventCallbacks.size() << "]";
+ oss << "[" << mEventCallbacks.Count() << "]";
DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_VECTOR_ANIMATION_MANAGER_PROCESS", oss.str().c_str());
}
}
#ifdef TRACE_ENABLED
if(gTraceFilter && gTraceFilter->IsTraceEnabled())
{
- if(mEventCallbacks.size() > 0u)
+ if(mEventCallbacks.Count() > 0u)
{
std::ostringstream oss;
- oss << "[" << mEventCallbacks.size() << "]";
+ oss << "[" << mEventCallbacks.Count() << "]";
DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_VECTOR_ANIMATION_MANAGER_PROCESS", oss.str().c_str());
}
}
#endif
- mEventCallbacks.clear();
+ mEventCallbacks.Clear();
Adaptor::Get().UnregisterProcessor(*this, true);
mProcessorRegistered = false;
#define DALI_TOOLKIT_INTERNAL_VECTOR_ANIMATION_MANAGER_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*/
// EXTERNAL INCLUDES
+#include <dali/integration-api/ordered-set.h>
#include <dali/integration-api/processor-interface.h>
#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/signals/callback.h>
class VectorAnimationManager : public Integration::Processor
{
public:
- struct LifecycleObserver
- {
- virtual void VectorAnimationManagerDestroyed() = 0;
- };
-
/**
* @brief Constructor.
*/
~VectorAnimationManager() override;
/**
- * Add a lifecycle observer
- * @param[in] observer The object watching this one
- */
- void AddObserver(LifecycleObserver& observer);
-
- /**
- * Remove a lifecycle observer
- * @param[in] observer The object watching this one
- */
- void RemoveObserver(LifecycleObserver& observer);
-
- /**
* Get the vector animation thread.
* @return A raw pointer pointing to the vector animation thread.
*/
VectorAnimationManager& operator=(const VectorAnimationManager& manager) = delete;
private:
- std::vector<std::unique_ptr<CallbackBase>> mEventCallbacks;
- std::vector<LifecycleObserver*> mLifecycleObservers;
- std::unique_ptr<VectorAnimationThread> mVectorAnimationThread;
- bool mProcessorRegistered;
+ Dali::Integration::OrderedSet<CallbackBase> mEventCallbacks; ///< Event triggered callback lists (owned)
+
+ std::unique_ptr<VectorAnimationThread> mVectorAnimationThread;
+ bool mProcessorRegistered : 1;
};
} // namespace Internal
mForward(true),
mUpdateFrameNumber(false),
mNeedAnimationFinishedTrigger(true),
+ mNeedForceRenderOnceTrigger(false),
mAnimationDataUpdated(false),
mDestroyTask(false),
mLoadRequest(false),
mLayerInfoCached(false),
mMarkerInfoCached(false),
mEnableFrameCache(false),
+ mNotifyAfterRasterization(false),
mSizeUpdated(false)
{
mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
{
mPlayState = PlayState::PAUSED;
+ // Ensure to render paused frame.
+ mNeedForceRenderOnceTrigger = true;
+
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
}
}
if(mStartFrame > mCurrentFrame)
{
mCurrentFrame = mStartFrame;
+
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
}
else if(mEndFrame < mCurrentFrame)
{
mCurrentFrame = mEndFrame;
+
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
}
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mImageUrl.GetUrl().c_str(), this);
mCurrentFrame = frameNumber;
mUpdateFrameNumber = false;
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
+
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
}
else
mForward = true;
mCurrentLoop = 0;
+ mNeedForceRenderOnceTrigger = true;
+
if(mVectorRenderer)
{
// Notify the Renderer that rendering is stopped.
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
}
+ // Forcely trigger render once if need.
+ if(mNotifyAfterRasterization || mNeedForceRenderOnceTrigger)
+ {
+ Mutex::ScopedLock lock(mMutex);
+ mVectorAnimationThread.RequestForceRenderOnce();
+ mNeedForceRenderOnceTrigger = false;
+ }
+
if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
{
mKeepAnimation = true;
SetCurrentFrameNumber(animationData.currentFrame);
}
+ if(animationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)
+ {
+ mNotifyAfterRasterization = animationData.notifyAfterRasterization;
+ }
+
if(animationData.resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
{
mVectorRenderer.InvalidateBuffer();
*/
enum ResendFlags
{
- RESEND_PLAY_RANGE = 1 << 0,
- RESEND_LOOP_COUNT = 1 << 1,
- RESEND_STOP_BEHAVIOR = 1 << 2,
- RESEND_LOOPING_MODE = 1 << 3,
- RESEND_CURRENT_FRAME = 1 << 4,
- RESEND_SIZE = 1 << 5,
- RESEND_PLAY_STATE = 1 << 6,
- RESEND_NEED_RESOURCE_READY = 1 << 7,
- RESEND_DYNAMIC_PROPERTY = 1 << 8
+ RESEND_PLAY_RANGE = 1 << 0,
+ RESEND_LOOP_COUNT = 1 << 1,
+ RESEND_STOP_BEHAVIOR = 1 << 2,
+ RESEND_LOOPING_MODE = 1 << 3,
+ RESEND_CURRENT_FRAME = 1 << 4,
+ RESEND_SIZE = 1 << 5,
+ RESEND_PLAY_STATE = 1 << 6,
+ RESEND_NEED_RESOURCE_READY = 1 << 7,
+ RESEND_DYNAMIC_PROPERTY = 1 << 8,
+ RESEND_NOTIFY_AFTER_RASTERIZATION = 1 << 9,
};
/**
width(0),
height(0),
loopCount(-1),
- playStateId(0)
+ playStateId(0),
+ notifyAfterRasterization(false)
{
}
AnimationData& operator=(const AnimationData& rhs)
{
resendFlag |= rhs.resendFlag; // OR resend flag
- playRange = rhs.playRange;
- playState = rhs.playState;
- stopBehavior = rhs.stopBehavior;
- loopingMode = rhs.loopingMode;
- currentFrame = rhs.currentFrame;
- width = rhs.width;
- height = rhs.height;
- loopCount = rhs.loopCount;
- playStateId = rhs.playStateId;
+ playRange = rhs.playRange;
+ playState = rhs.playState;
+ stopBehavior = rhs.stopBehavior;
+ loopingMode = rhs.loopingMode;
+ currentFrame = rhs.currentFrame;
+ width = rhs.width;
+ height = rhs.height;
+ loopCount = rhs.loopCount;
+ playStateId = rhs.playStateId;
+ notifyAfterRasterization = rhs.notifyAfterRasterization;
dynamicProperties.insert(dynamicProperties.end(), rhs.dynamicProperties.begin(), rhs.dynamicProperties.end());
return *this;
}
uint32_t height;
int32_t loopCount;
uint32_t playStateId;
+ bool notifyAfterRasterization;
};
/**
*/
bool IsAnimating();
+ void KeepRasterizedBuffer(bool enableFrameCache)
+ {
+ mEnableFrameCache = enableFrameCache;
+ }
+
+ bool IsKeptRasterizedBuffer() const
+ {
+ return mEnableFrameCache;
+ }
+
public: // Implementation of AsyncTask
/**
* @copydoc Dali::AsyncTask::Process()
return "VectorAnimationTask";
}
- void KeepRasterizedBuffer(bool enableFrameCache)
- {
- mEnableFrameCache = enableFrameCache;
- }
-
- bool IsKeptRasterizedBuffer()
- {
- return mEnableFrameCache;
- }
-
private:
/**
* @brief Loads the animation file.
bool mForward : 1;
bool mUpdateFrameNumber : 1;
bool mNeedAnimationFinishedTrigger : 1;
+ bool mNeedForceRenderOnceTrigger : 1;
bool mAnimationDataUpdated : 1;
bool mDestroyTask : 1;
bool mLoadRequest : 1;
mutable bool mLayerInfoCached : 1;
mutable bool mMarkerInfoCached : 1;
bool mEnableFrameCache : 1;
+ bool mNotifyAfterRasterization : 1;
bool mSizeUpdated : 1;
};
mSleepThread(MakeCallback(this, &VectorAnimationThread::OnAwakeFromSleep)),
mConditionalWait(),
mEventTriggerMutex(),
+ mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+ mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
mNeedToSleep(false),
mDestroyThread(false),
- mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
- mTraceFactory(Dali::Adaptor::Get().GetTraceFactory())
+ mEventTriggered(false),
+ mForceRenderOnce(false)
{
mAsyncTaskManager = Dali::AsyncTaskManager::Get();
mSleepThread.Start();
}
}
+void VectorAnimationThread::RequestForceRenderOnce()
+{
+ Mutex::ScopedLock lock(mEventTriggerMutex);
+ if(!mDestroyThread)
+ {
+ mForceRenderOnce = true;
+
+ if(!mEventTriggered)
+ {
+ mEventTrigger->Trigger();
+ mEventTriggered = true;
+ }
+ }
+}
+
void VectorAnimationThread::Run()
{
SetThreadName("VectorAnimationThread");
}
CallbackBase::Execute(*callbackPair.first, callbackPair.second);
}
+ // Request update once if we need.
+ {
+ Mutex::ScopedLock lock(mEventTriggerMutex);
+ if(!mDestroyThread && mForceRenderOnce)
+ {
+ mForceRenderOnce = false;
+ if(Dali::Adaptor::IsAvailable())
+ {
+ Dali::Adaptor::Get().UpdateOnce();
+ }
+ }
+ }
}
std::pair<CallbackBase*, uint32_t> VectorAnimationThread::GetNextEventCallback()
*/
void RemoveEventTriggerCallbacks(CallbackBase* callback);
+ /**
+ * @brief Request to event callback from rasterize thread. This is called when we want to ensure rendering next frame.
+ */
+ void RequestForceRenderOnce();
+
protected:
/**
* @brief The entry function of the animation thread.
std::chrono::time_point<std::chrono::steady_clock> mSleepTimePoint;
const Dali::LogFactoryInterface& mLogFactory;
const Dali::TraceFactoryInterface& mTraceFactory;
- bool mNeedToSleep;
- bool mDestroyThread;
+
+ bool mNeedToSleep : 1;
+ bool mDestroyThread : 1;
};
private:
ConditionalWait mConditionalWait;
Mutex mEventTriggerMutex;
std::unique_ptr<EventThreadCallback> mEventTrigger{};
- bool mNeedToSleep;
- bool mDestroyThread;
- bool mEventTriggered{false};
const Dali::LogFactoryInterface& mLogFactory;
const Dali::TraceFactoryInterface& mTraceFactory;
Dali::AsyncTaskManager mAsyncTaskManager;
+
+ bool mNeedToSleep : 1;
+ bool mDestroyThread : 1;
+ bool mEventTriggered : 1;
+ bool mForceRenderOnce : 1;
};
} // namespace Internal
TextureSet textureSet = TextureSet::New();
Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
textureSet.SetTexture(0u, lookupTexture);
- Dali::WrapMode::Type wrap = GetWrapMode(mGradient->GetSpreadMethod());
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(wrap, wrap);
- textureSet.SetSampler(0u, sampler);
+ Dali::WrapMode::Type wrap = GetWrapMode(mGradient->GetSpreadMethod());
+ if(wrap != Dali::WrapMode::DEFAULT)
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode(wrap, wrap);
+ textureSet.SetSampler(0u, sampler);
+ }
mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
}
EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
- if(!atlasing)
+ if(!atlasing && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode(mWrapModeU, mWrapModeV);
else
{
mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId);
- if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) && mTextures)
+ if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) &&
+ mTextures &&
+ (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode(mWrapModeU, mWrapModeV);
}
else
{
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(mWrapModeU, mWrapModeV);
- textureInformation.textureSet.SetSampler(0u, sampler);
+ if(mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT)
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+ textureInformation.textureSet.SetSampler(0u, sampler);
+ }
mImpl->mRenderer.SetTextures(textureInformation.textureSet);
ComputeTextureSize();
// Load the auxiliary image
mAuxiliaryTextureSet = textureManager.LoadTexture(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, maskingDataPtr, synchronousLoading, mAuxiliaryTextureId, atlasRect, atlasRectSize, atlasing, loadingStatus, this, nullptr, imageAtlasManagerPtr, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad);
- if(mAuxiliaryTextureSet)
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(WrapMode::DEFAULT, WrapMode::DEFAULT);
- mAuxiliaryTextureSet.SetSampler(0u, sampler);
- }
-
// If synchronousLoading is true, we can check the auxiliaryResource's status now.
if(synchronousLoading)
{
}
if(loadSuccess)
{
- mAuxiliaryTextureSet = textureInformation.textureSet;
- if(mAuxiliaryTextureSet)
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode(WrapMode::DEFAULT, WrapMode::DEFAULT);
- mAuxiliaryTextureSet.SetSampler(0u, sampler);
- }
-
+ mAuxiliaryTextureSet = textureInformation.textureSet;
mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::READY;
}
else
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
{
DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
-const int CUSTOM_PROPERTY_COUNT(2); // uTextColorAnimatable, uHasMultipleTextColors
+const int CUSTOM_PROPERTY_COUNT(3); // uTextColorAnimatable, uHasMultipleTextColors, requireRender
/**
* Return Property index for the given string key
void OpacityConstraint(float& current, const PropertyInputContainer& inputs)
{
// Make zero if the alpha value of text color is zero to skip rendering text
- if(EqualsZero(inputs[0]->GetVector4().a))
+ if(EqualsZero(inputs[0]->GetVector4().a) && !inputs[1]->GetBoolean())
{
current = 0.0f;
}
mHasMultipleTextColorsIndex(Property::INVALID_INDEX),
mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX),
mTextColorAnimatableIndex(Property::INVALID_INDEX),
- mRendererUpdateNeeded(false)
+ mTextRequireRenderPropertyIndex(Property::INVALID_INDEX),
+ mRendererUpdateNeeded(false),
+ mTextRequireRender(false)
{
// Enable the pre-multiplied alpha to improve the text quality
mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
mImpl->mRenderer = VisualRenderer::New(geometry, shader);
mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
+ mTextRequireRenderPropertyIndex = mImpl->mRenderer.RegisterUniqueProperty("requireRender", mTextRequireRender);
mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast<float>(false));
}
// VisualRenderer::Property::OPACITY uses same animatable property internally.
mOpacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
mOpacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+ mOpacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex));
}
mOpacityConstraint.Apply();
}
UpdateRenderer();
}
-void TextVisual::RemoveRenderer(Actor& actor)
+void TextVisual::RemoveRenderer(Actor& actor, bool removeDefaultRenderer)
{
for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter)
{
Renderer renderer = (*iter);
- if(renderer)
+ if(renderer &&
+ (removeDefaultRenderer || (renderer != mImpl->mRenderer)))
{
// Removes the renderer from the actor.
actor.RemoveRenderer(renderer);
mOpacityConstraint.Remove();
}
- RemoveRenderer(actor);
+ RemoveRenderer(actor, true);
// Resets the control handle.
mControl.Reset();
const bool isWidthRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.z) < Math::MACHINE_EPSILON_1000;
const bool isHeightRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.w) < Math::MACHINE_EPSILON_1000;
+ const float controlWidth = mImpl->mControlSize.width;
+ const float controlHeight = mImpl->mControlSize.height;
+
// Round the size and offset to avoid pixel alignement issues.
- relayoutSize.width = floorf(0.5f + (isWidthRelative ? mImpl->mControlSize.width * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width));
- relayoutSize.height = floorf(0.5f + (isHeightRelative ? mImpl->mControlSize.height * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height));
+ relayoutSize.width = floorf(0.5f + (isWidthRelative ? controlWidth * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width));
+ relayoutSize.height = floorf(0.5f + (isHeightRelative ? controlHeight * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height));
auto textLengthUtf32 = mController->GetNumberOfCharacters();
if((fabsf(relayoutSize.width) < Math::MACHINE_EPSILON_1000) || (fabsf(relayoutSize.height) < Math::MACHINE_EPSILON_1000) || textLengthUtf32 == 0u)
{
// Remove the texture set and any renderer previously set.
- RemoveRenderer(control);
+ RemoveRenderer(control, true);
// Nothing else to do if the relayout size is zero.
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
mRendererUpdateNeeded = false;
// Remove the texture set and any renderer previously set.
- RemoveRenderer(control);
+ // Note, we don't need to remove the mImpl->Renderer, since it will be added again after AddRenderer call.
+ RemoveRenderer(control, false);
if((relayoutSize.width > Math::MACHINE_EPSILON_1000) &&
(relayoutSize.height > Math::MACHINE_EPSILON_1000))
shadowEnabled = true;
}
- const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
- const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
- const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
- const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
- const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
- const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
- const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
- const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet();
- const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet);
- const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
+ const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+ const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
+ const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
+ const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
+ const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
+ const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
+ const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
+ const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet();
+ const bool cutoutEnabled = mController->IsTextCutout();
+ const bool backgroundWithCutoutEnabled = mController->GetTextModel()->IsBackgroundWithCutoutEnabled();
+ const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled);
+ const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
+
+ // if background with cutout is enabled, This text visual must render the entire control size.
+
+ if(cutoutEnabled)
+ {
+ relayoutSize = Vector2(controlWidth, controlHeight);
+ mImpl->mTransform.mSize.width = controlWidth;
+ mImpl->mTransform.mSize.height = controlHeight;
+ mImpl->mTransform.mOffset.x = 0;
+ mImpl->mTransform.mOffset.y = 0;
+ }
AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
Renderer renderer = (*iter);
if(renderer)
{
+ // Note, AddRenderer will ignore renderer if it is already added. @SINCE 2_3.22
actor.AddRenderer(renderer);
if(renderer != mImpl->mRenderer)
// VisualRenderer::Property::OPACITY uses same animatable property internally.
Constraint opacityConstraint = Constraint::New<float>(renderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+ opacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex));
opacityConstraint.Apply();
}
}
TextureSet TextVisual::GetTextTexture(const Vector2& size)
{
+ const bool cutoutEnabled = mController->IsTextCutout();
+
// Filter mode needs to be set to linear to produce better quality while scaling.
Sampler sampler = Sampler::New();
sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR);
TextureSet textureSet = TextureSet::New();
// Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
- Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor()) ? Pixel::RGBA8888 : Pixel::L8;
+ Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor() || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8;
// Check the text direction
Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
-
+ uint32_t textureSetIndex = 0u;
// Create a texture for the text without any styles
- PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
- uint32_t textureSetIndex = 0u;
- AddTexture(textureSet, data, sampler, textureSetIndex);
- ++textureSetIndex;
+ Devel::PixelBuffer cutoutData;
+ float cutoutAlpha = mController->GetTextModel()->GetDefaultColor().a;
+ if(cutoutEnabled)
+ {
+ cutoutData = mTypesetter->RenderWithPixelBuffer(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
+
+ // Make transparent buffer.
+ // If the cutout is enabled, a separate texture is not used for the text.
+ Devel::PixelBuffer buffer = mTypesetter->CreateFullBackgroundBuffer(1, 1, Vector4(0.f, 0.f ,0.f ,0.f));
+ PixelData data = Devel::PixelBuffer::Convert(buffer);
+ AddTexture(textureSet, data, sampler, textureSetIndex);
+ ++textureSetIndex;
+ }
+ else
+ {
+ PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
+ AddTexture(textureSet, data, sampler, textureSetIndex);
+ ++textureSetIndex;
+ }
+
if(mTextShaderFeatureCache.IsEnabledStyle())
{
// Create RGBA texture for all the text styles that render in the background (without the text itself)
- PixelData styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+ PixelData styleData;
+
+ if(cutoutEnabled && cutoutData)
+ {
+ styleData = mTypesetter->RenderWithCutout(size, textDirection, cutoutData, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888, cutoutAlpha);
+ }
+ else
+ {
+ styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+ }
+
AddTexture(textureSet, styleData, sampler, textureSetIndex);
++textureSetIndex;
}
return shader;
}
+void TextVisual::SetRequireRender(bool requireRender)
+{
+ mTextRequireRender = requireRender;
+ if(mImpl->mRenderer)
+ {
+ mImpl->mRenderer.SetProperty(mTextRequireRenderPropertyIndex, mTextRequireRender);
+ }
+}
+
} // namespace Internal
} // namespace Toolkit
#define DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
};
/**
+ * @brief Set the text to be always rendered
+ * @param[in] visual The text visual.
+ * @param[in] requireRender Whether to text always rendered.
+ */
+ static void SetRequireRender(Toolkit::Visual::Base visual, bool requireRender)
+ {
+ GetVisualObject(visual).SetRequireRender(requireRender);
+ };
+
+ /**
* @brief Instantly updates the renderer
* @param[in] visual The text visual.
*/
/**
* @brief Removes the text's renderer.
*/
- void RemoveRenderer(Actor& actor);
+ void RemoveRenderer(Actor& actor, bool removeDefaultRenderer);
/**
* @brief Create a texture in textureSet and add it.
Shader GetTextShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder);
/**
+ * @brief Set the text to be always rendered
+ * @param[in] requireRender Whether to text always rendered.
+ */
+ void SetRequireRender(bool requireRender);
+
+ /**
* @brief Retrieve the TextVisual object.
* @param[in] visual A handle to the TextVisual
* @return The TextVisual object
Property::Index mHasMultipleTextColorsIndex; ///< The index of uHasMultipleTextColors proeprty.
Property::Index mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control.
Property::Index mTextColorAnimatableIndex; ///< The index of uTextColorAnimatable property.
+ Property::Index mTextRequireRenderPropertyIndex; ///< The index of requireRender property.
bool mRendererUpdateNeeded : 1; ///< The flag to indicate whether the renderer needs to be updated.
+ bool mTextRequireRender : 1; ///< The flag to indicate whether the text needs to be rendered.
RendererContainer mRendererList;
};
const char* TOKEN_DURATION("duration");
const char* TOKEN_DELAY("delay");
const char* TOKEN_ALPHA_FUNCTION("alphaFunction");
+const char* TOKEN_ANIMATION_TYPE("animationType");
DALI_ENUM_TO_STRING_TABLE_BEGIN(ALPHA_FUNCTION_BUILTIN)
DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, LINEAR)
}
}
}
+ else if(key == TOKEN_ANIMATION_TYPE)
+ {
+ if((value.GetType() == Property::STRING))
+ {
+ if(value.Get<std::string>() == "TO")
+ {
+ animator->animationType = AnimationType::TO;
+ }
+ else if(value.Get<std::string>() == "BETWEEN")
+ {
+ animator->animationType = AnimationType::BETWEEN;
+ }
+ else if(value.Get<std::string>() == "BY")
+ {
+ animator->animationType = AnimationType::BY;
+ }
+ }
+ }
}
}
}
class TransitionData : public BaseObject
{
public:
+ enum class AnimationType : uint8_t
+ {
+ TO, ///< Animating TO the given value
+ BY, ///< Animating BY the given value
+ BETWEEN ///< Animating BETWEEN key-frames
+ };
+
/**
* @brief TransitionDataElement Describes one animator of an transition.
*/
alphaFunction(AlphaFunction::DEFAULT),
timePeriodDelay(0.0f),
timePeriodDuration(1.0f),
+ animationType(AnimationType::TO),
animate(false)
{
}
Dali::AlphaFunction alphaFunction;
float timePeriodDelay;
float timePeriodDuration;
+ AnimationType animationType;
bool animate;
};
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
#include <dali-toolkit/internal/helpers/property-helper.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
mMixColor(Color::WHITE),
mControlSize(Vector2::ZERO),
mDecorationData(nullptr),
- mDepthIndex(0.0f),
+ mDepthIndex(Toolkit::DepthIndex::AUTO_INDEX),
mFittingMode(fittingMode),
mFlags(0),
mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
#include <dali/public-api/rendering/visual-renderer.h>
//INTERNAL HEARDER
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
void Visual::Base::SetDepthIndex(int index)
{
- mImpl->mDepthIndex = index;
- if(mImpl->mRenderer)
+ // Clamp input value as valid range.
+ Dali::ClampInPlace(index, static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX), static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX));
+
+ if(mImpl->mDepthIndex != index)
{
- mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+ mImpl->mDepthIndex = index;
+ if(mImpl->mRenderer)
+ {
+ mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+ }
}
}
if(mImpl->mRenderer)
{
mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
- mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+ if(mImpl->mDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
+ {
+ mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, static_cast<int>(DepthIndex::CONTENT));
+ }
+ else
+ {
+ mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+ }
}
mImpl->mFlags |= Impl::IS_ON_SCENE;
{
if(animator.initialValue.GetType() != Property::NONE)
{
- mImpl->mRenderer.SetProperty(index, initialValue);
+ if(animator.animationType != TransitionData::AnimationType::BETWEEN)
+ {
+ mImpl->mRenderer.SetProperty(index, initialValue);
+ }
}
if(!transition)
transition = Dali::Animation::New(0.1f);
}
- transition.AnimateTo(Property(mImpl->mRenderer, index),
- targetValue,
- animator.alphaFunction,
- TimePeriod(animator.timePeriodDelay,
- animator.timePeriodDuration));
+ if(animator.animationType == TransitionData::AnimationType::BETWEEN)
+ {
+ Dali::KeyFrames keyFrames = Dali::KeyFrames::New();
+ keyFrames.Add(0.0f, animator.initialValue);
+ keyFrames.Add(1.0f, animator.targetValue);
+ transition.AnimateBetween(Property(mImpl->mRenderer, index),keyFrames, TimePeriod(animator.timePeriodDelay, animator.timePeriodDuration));
+ }
+ else if(animator.animationType == TransitionData::AnimationType::BY)
+ {
+ // To Do
+ DALI_LOG_WARNING("AnimationType::By is not supported yet. \n");
+ }
+ else
+ {
+ transition.AnimateTo(Property(mImpl->mRenderer, index),
+ targetValue,
+ animator.alphaFunction,
+ TimePeriod(animator.timePeriodDelay,
+ animator.timePeriodDuration));
+ }
}
}
}
const char* const FAST_TRACK_UPLOADING_NAME("fastTrackUploading");
const char* const ENABLE_BROKEN_IMAGE("enableBrokenImage");
const char* const ENABLE_FRAME_CACHE("enableFrameCache");
+const char* const NOTIFY_AFTER_RASTERIZATION("notifyAfterRasterization");
// Text visual
const char* const TEXT_PROPERTY("text");
extern const char* const FAST_TRACK_UPLOADING_NAME;
extern const char* const ENABLE_BROKEN_IMAGE;
extern const char* const ENABLE_FRAME_CACHE;
+extern const char* const NOTIFY_AFTER_RASTERIZATION;
// Text visual
extern const char* const TEXT_PROPERTY;
case Actor::Property::VISIBLE:
{
auto* accessible = GetAccessibleObject();
- if(DALI_LIKELY(accessible))
+ if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
{
accessible->EmitVisible(Self().GetProperty<bool>(Actor::Property::VISIBLE));
}
* @brief name "enableTransitionEffect", type Boolean
*
* This effect is a crossfade effect when the image is replaced.
- * the default duration of the crossfade effect is 1.5 seconds.
+ * the default duration of the crossfade effect is 0.3 seconds.
* if the placeholder is enabled, the cross effect applies when the image is changed from a placeholder image to a new image.
* if not, the cross effect applies when a new image is shown or is changed from the previous image to a new image.
* @SINCE_2_2.24
*/
ENABLE_TRANSITION_EFFECT,
+ /**
+ * @brief name "transitionEffectOption", type Map
+ *
+ * This option is for transition effect when the image is replaced.
+ * if not, the cross effect use default option.
+ * @SINCE_2_2.24
+ */
+ TRANSITION_EFFECT_OPTION,
+
// Animatable properties
/**
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 18;
+const unsigned int TOOLKIT_MICRO_VERSION = 24;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
cout << "====================================================================" << endl;
BuiltInFilesGenerator generator(outDir);
+ bool shaderGenerated = false;
for(auto& file : fs::directory_iterator(inDir))
{
if(shaderFile.is_open())
{
fs::path outFilePath(GetShaderOutputFilePath(outDir, filename));
- GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
generator.Add(std::move(shaderVariableName), outFilePath.filename().string());
+ if(fs::exists(outFilePath))
+ {
+ // Only overwrite if input file is newer than output file
+ fs::file_time_type inFileTime = fs::last_write_time(path);
+ fs::file_time_type outFileTime = fs::last_write_time(outFilePath);
+ if(outFileTime > inFileTime)
+ {
+ continue;
+ }
+ }
+ GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
+ shaderGenerated = true;
}
break;
}
}
}
- if(generateBuiltInFiles)
+ if(generateBuiltInFiles && shaderGenerated)
{
generator.Generate();
}
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.3.18
+Version: 2.3.24
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT