From: Richard Huang Date: Fri, 7 Jan 2022 12:11:56 +0000 (+0000) Subject: Add keyboard support and animation control in SceneLoader demo X-Git-Tag: submit/tizen/20220119.054331^2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0dea46410eb7b227b0358652e0a5834a834988e0;p=platform%2Fcore%2Fuifw%2Fdali-demo.git Add keyboard support and animation control in SceneLoader demo Change-Id: Ic69ba19f05ab957f591923cd1381046568685a26 --- diff --git a/examples/scene-loader/scene-loader-example.cpp b/examples/scene-loader/scene-loader-example.cpp index 13d7681e..417ba6bc 100644 --- a/examples/scene-loader/scene-loader-example.cpp +++ b/examples/scene-loader/scene-loader-example.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -15,6 +15,7 @@ * */ #include "scene-loader-example.h" +#include #include #include #include @@ -32,6 +33,7 @@ #include "dali/public-api/events/key-event.h" #include "dali/public-api/object/property-array.h" #include "dali/public-api/render-tasks/render-task-list.h" +#include "scene-loader-extension.h" using namespace Dali; using namespace Dali::Toolkit; @@ -80,10 +82,11 @@ StringVector ListFiles( TextLabel MakeLabel(std::string msg) { - TextLabel label = TextLabel::New(msg); + TextLabel label = TextLabel::New(" " + msg); label.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); label.SetProperty(TextLabel::Property::TEXT_COLOR, Color::WHITE); label.SetProperty(TextLabel::Property::PIXEL_SIZE, ITEM_HEIGHT * 4 / 7); + label.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER"); SetActorCentered(label); return label; } @@ -108,6 +111,7 @@ struct ItemFactoryImpl : Dali::Toolkit::ItemFactory { auto label = MakeLabel(mSceneNames[itemId]); mTapDetector.Attach(label); + label.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); return label; } }; @@ -172,7 +176,7 @@ void ConfigureBlendShapeShaders(ResourceBundle& resources, const SceneDefinition } } -Actor LoadScene(std::string sceneName, CameraActor camera) +Actor LoadScene(std::string sceneName, CameraActor camera, std::vector* animations, Animation& animation) { ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) { return Application::GetResourcePath() + RESOURCE_TYPE_DIRS[type]; @@ -185,12 +189,13 @@ Actor LoadScene(std::string sceneName, CameraActor camera) std::vector animGroups; std::vector cameraParameters; std::vector lights; - std::vector animations; + + animations->clear(); LoadResult output{ resources, scene, - animations, + *animations, animGroups, cameraParameters, lights}; @@ -262,13 +267,14 @@ Actor LoadScene(std::string sceneName, CameraActor camera) } } - if(!animations.empty()) + if(!animations->empty()) { auto getActor = [&root](const std::string& name) { return root.FindChildByName(name); }; - animations[0].ReAnimate(getActor).Play(); + animation = (*animations)[0].ReAnimate(getActor); + animation.Play(); } return root; @@ -277,7 +283,8 @@ Actor LoadScene(std::string sceneName, CameraActor camera) } // namespace SceneLoaderExample::SceneLoaderExample(Dali::Application& app) -: mApp(app) +: mApp(app), + mSceneLoaderExtension(new SceneLoaderExtension()) { if(!std::getenv("DALI_APPLICATION_PACKAGE")) { @@ -295,6 +302,8 @@ SceneLoaderExample::SceneLoaderExample(Dali::Application& app) app.TerminateSignal().Connect(this, &SceneLoaderExample::OnTerminate); } +SceneLoaderExample::~SceneLoaderExample() = default; + void SceneLoaderExample::OnInit(Application& app) { // get scenes @@ -346,13 +355,20 @@ void SceneLoaderExample::OnInit(Application& app) Vector3 windowSize(window.GetSize()); auto itemLayout = DefaultItemLayout::New(DefaultItemLayout::LIST); - itemLayout->SetItemSize(Vector3(windowSize.x, ITEM_HEIGHT, 1.f)); + itemLayout->SetItemSize(Vector3(windowSize.x * 0.9f, ITEM_HEIGHT, 1.f)); items.AddLayout(*itemLayout); navigationView.Push(items); mItemLayout = itemLayout; mItemView = items; + mItemView.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); + KeyboardFocusManager::Get().PreFocusChangeSignal().Connect(this, &SceneLoaderExample::OnKeyboardPreFocusChange); + KeyboardFocusManager::Get().FocusedActorEnterKeySignal().Connect(this, &SceneLoaderExample::OnKeyboardFocusedActorActivated); + KeyboardFocusManager::Get().FocusChangedSignal().Connect(this, &SceneLoaderExample::OnKeyboardFocusChanged); + + SetActorCentered(KeyboardFocusManager::Get().GetFocusIndicatorActor()); + // camera auto camera = CameraActor::New(); camera.SetInvertYAxis(true); @@ -366,7 +382,36 @@ void SceneLoaderExample::OnInit(Application& app) mTapDetector = tapDetector; // activate layout - mItemView.ActivateLayout(0, windowSize, 1.f); + mItemView.ActivateLayout(0, windowSize, 0.f); + + mSceneLoaderExtension->SetSceneLoader(this); +} + +Actor SceneLoaderExample::OnKeyboardPreFocusChange(Actor current, Actor proposed, Control::KeyboardFocus::Direction direction) +{ + if(!current && !proposed) + { + return mItemView; + } + + return proposed; +} + +void SceneLoaderExample::OnKeyboardFocusedActorActivated(Actor activatedActor) +{ + if(activatedActor) + { + OnTap(activatedActor, Dali::TapGesture()); + } +} + +void SceneLoaderExample::OnKeyboardFocusChanged(Actor originalFocusedActor, Actor currentFocusedActor) +{ + if(currentFocusedActor) + { + auto itemId = mItemView.GetItemId(currentFocusedActor); + mItemView.ScrollToItem(itemId, 0.1f); + } } void SceneLoaderExample::OnTerminate(Application& app) @@ -397,12 +442,21 @@ void SceneLoaderExample::OnKey(const KeyEvent& e) mNavigationView.Pop(); mScene.Reset(); + + if(mActivatedActor) + { + KeyboardFocusManager::Get().SetCurrentFocusActor(mActivatedActor); + } } else { mApp.Quit(); } } + else + { + mSceneLoaderExtension->OnKey(e); + } } } @@ -424,6 +478,8 @@ void SceneLoaderExample::OnPan(Actor actor, const PanGesture& pan) void SceneLoaderExample::OnTap(Dali::Actor actor, const Dali::TapGesture& tap) { + mActivatedActor = actor; + auto id = mItemView.GetItemId(actor); try @@ -432,7 +488,7 @@ void SceneLoaderExample::OnTap(Dali::Actor actor, const Dali::TapGesture& tap) auto renderTasks = window.GetRenderTaskList(); renderTasks.RemoveTask(mSceneRender); - auto scene = LoadScene(mSceneNames[id], mSceneCamera); + auto scene = LoadScene(mSceneNames[id], mSceneCamera, &mSceneAnimations, mCurrentAnimation); auto sceneRender = renderTasks.CreateTask(); sceneRender.SetCameraActor(mSceneCamera); @@ -452,4 +508,6 @@ void SceneLoaderExample::OnTap(Dali::Actor actor, const Dali::TapGesture& tap) } mNavigationView.Push(mScene); + + mSceneLoaderExtension->ConnectTouchSignals(); } diff --git a/examples/scene-loader/scene-loader-example.h b/examples/scene-loader/scene-loader-example.h index b18c8302..a516dbe8 100644 --- a/examples/scene-loader/scene-loader-example.h +++ b/examples/scene-loader/scene-loader-example.h @@ -1,7 +1,7 @@ #ifndef SCENE_LAUNCHER_H_ #define SCENE_LAUNCHER_H_ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -16,6 +16,8 @@ * limitations under the License. * */ + +#include #include "dali-scene-loader/public-api/animation-definition.h" #include "dali-scene-loader/public-api/camera-parameters.h" #include "dali-scene-loader/public-api/node-definition.h" @@ -31,11 +33,13 @@ #include "dali/public-api/render-tasks/render-task.h" #include "dali/public-api/signals/connection-tracker.h" +class SceneLoaderExtension; + class SceneLoaderExample : public Dali::ConnectionTracker { public: SceneLoaderExample(Dali::Application& app); - ~SceneLoaderExample() = default; + ~SceneLoaderExample(); private: // data Dali::Application& mApp; @@ -50,13 +54,22 @@ private: // data Dali::CameraActor mSceneCamera; Dali::RenderTask mSceneRender; - Dali::Actor mScene; Dali::Quaternion mCameraOrientationInv; Dali::TapGestureDetector mTapDetector; Dali::PanGestureDetector mPanDetector; + Dali::Actor mActivatedActor; + +public: + Dali::Actor mScene; + + std::vector mSceneAnimations; + Dali::Animation mCurrentAnimation; + + std::unique_ptr mSceneLoaderExtension; + private: // methods void OnInit(Dali::Application& app); void OnTerminate(Dali::Application& app); @@ -64,6 +77,10 @@ private: // methods void OnKey(const Dali::KeyEvent& e); void OnPan(Dali::Actor actor, const Dali::PanGesture& pan); void OnTap(Dali::Actor actor, const Dali::TapGesture& tap); + + Dali::Actor OnKeyboardPreFocusChange(Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocus::Direction direction); + void OnKeyboardFocusedActorActivated(Dali::Actor activatedActor); + void OnKeyboardFocusChanged(Dali::Actor originalFocusedActor, Dali::Actor currentFocusedActor); }; #endif //SCENE_LAUNCHER_H_ diff --git a/examples/scene-loader/scene-loader-extension.h b/examples/scene-loader/scene-loader-extension.h new file mode 100644 index 00000000..e937234e --- /dev/null +++ b/examples/scene-loader/scene-loader-extension.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +class SceneLoaderExtension : public Dali::ConnectionTracker +{ +public: + SceneLoaderExtension() + : mSceneLoader(nullptr), + mCurrentAnimationIndex(ANIMATION_IDLE) + { + } + + ~SceneLoaderExtension() = default; // Nothing to do in destructor + + void SetSceneLoader(SceneLoaderExample* sceneLoader) + { + mSceneLoader = sceneLoader; + } + + void ConnectTouchSignals() + { + // This is a temporary hack for now to manually connect these signals. + // We should connect these signals automatically when loading the scene. + + if(mSceneLoader) + { + ConnectTouchSignal(ICON_IDLE); + ConnectTouchSignal(ICON_SQUAT); + ConnectTouchSignal(ICON_JUMPING_JACK); + ConnectTouchSignal(ICON_LUNGE); + } + } + + void OnKey(const Dali::KeyEvent& e) + { + // This is a temporary hack for now to manually handle these key events. + // We should links them to the animations automatically when loading the scene. + + switch(e.GetKeyCode()) + { + case KEY_ONE: + { + PlaySceneAnimation(ANIMATION_IDLE); + break; + } + case KEY_TWO: + { + PlaySceneAnimation(ANIMATION_IDLE_TO_SQUAT); + break; + } + case KEY_THREE: + { + PlaySceneAnimation(ANIMATION_IDLE_TO_JUMPING_JACK); + break; + } + case KEY_FOUR: + { + PlaySceneAnimation(ANIMATION_IDLE_TO_LUNGE); + break; + } + default: + break; + } + } + +private: + bool PlaySceneAnimation(unsigned int animationIndex) + { + if(mSceneLoader && mSceneLoader->mScene) + { + if(mSceneLoader->mCurrentAnimation && + mCurrentAnimationIndex != ANIMATION_IDLE && + mSceneLoader->mCurrentAnimation.GetState() != Dali::Animation::STOPPED) + { + return false; + } + + auto root = mSceneLoader->mScene; + auto getActor = [&root](const std::string& name) { + return root.FindChildByName(name); + }; + + if(mSceneLoader->mSceneAnimations.size() > animationIndex) + { + mCurrentAnimationIndex = animationIndex; + mSceneLoader->mCurrentAnimation = mSceneLoader->mSceneAnimations[animationIndex].ReAnimate(getActor); + mSceneLoader->mCurrentAnimation.FinishedSignal().Connect(this, &SceneLoaderExtension::OnAnimationFinished); + mSceneLoader->mCurrentAnimation.Play(); + } + } + + return true; + } + + void ConnectTouchSignal(const std::string actorName) + { + if(mSceneLoader && mSceneLoader->mScene) + { + auto actor = mSceneLoader->mScene.FindChildByName(actorName); + if(actor) + { + actor.TouchedSignal().Connect(this, &SceneLoaderExtension::OnTouch); + } + } + } + + void OnAnimationFinished(Dali::Animation& source) + { + switch(mCurrentAnimationIndex) + { + case ANIMATION_IDLE_TO_SQUAT: + { + PlaySceneAnimation(ANIMATION_SQUAT_TO_IDLE); + break; + } + case ANIMATION_IDLE_TO_JUMPING_JACK: + { + PlaySceneAnimation(ANIMATION_JUMPING_JACK); + break; + } + case ANIMATION_JUMPING_JACK: + { + PlaySceneAnimation(ANIMATION_JUMPING_JACK_TO_IDLE); + break; + } + case ANIMATION_IDLE_TO_LUNGE: + { + PlaySceneAnimation(ANIMATION_LUNGE); + break; + } + case ANIMATION_LUNGE: + { + PlaySceneAnimation(ANIMATION_LUNGE_TO_IDLE); + break; + } + default: + { + mCurrentAnimationIndex = ANIMATION_IDLE; + break; + } + break; + } + } + + bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& touch) + { + bool processed = false; + + if(touch.GetPointCount() > 0) + { + if(touch.GetState(0) == Dali::PointState::DOWN) + { + auto actorName = actor.GetProperty(Dali::Actor::Property::NAME); + + if(ICON_IDLE == actorName) + { + processed = PlaySceneAnimation(ANIMATION_IDLE); + } + else if(ICON_SQUAT == actorName) + { + processed = PlaySceneAnimation(ANIMATION_IDLE_TO_SQUAT); + } + else if(ICON_JUMPING_JACK == actorName) + { + processed = PlaySceneAnimation(ANIMATION_IDLE_TO_JUMPING_JACK); + } + else if(ICON_LUNGE == actorName) + { + processed = PlaySceneAnimation(ANIMATION_IDLE_TO_LUNGE); + } + } + } + return processed; + } + +private: + static constexpr unsigned int KEY_ONE = 10; + static constexpr unsigned int KEY_TWO = 11; + static constexpr unsigned int KEY_THREE = 12; + static constexpr unsigned int KEY_FOUR = 13; + + // Idle animation + static constexpr unsigned int ANIMATION_IDLE = 0; + // Squat animation + static constexpr unsigned int ANIMATION_IDLE_TO_SQUAT = 3; + static constexpr unsigned int ANIMATION_SQUAT_TO_IDLE = 15; + // JumpingJack animation + static constexpr unsigned int ANIMATION_IDLE_TO_JUMPING_JACK = 1; + static constexpr unsigned int ANIMATION_JUMPING_JACK = 5; + static constexpr unsigned int ANIMATION_JUMPING_JACK_TO_IDLE = 6; + // Lunge animation + static constexpr unsigned int ANIMATION_IDLE_TO_LUNGE = 2; + static constexpr unsigned int ANIMATION_LUNGE = 9; + static constexpr unsigned int ANIMATION_LUNGE_TO_IDLE = 10; + + inline static const std::string ICON_IDLE = "Idle"; + inline static const std::string ICON_SQUAT = "Squat"; + inline static const std::string ICON_JUMPING_JACK = "JumpingJack"; + inline static const std::string ICON_LUNGE = "Lunge"; + + SceneLoaderExample* mSceneLoader; + unsigned int mCurrentAnimationIndex; +};