diff options
author | crupest <crupest@outlook.com> | 2018-09-19 01:15:01 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-09-19 01:15:01 +0800 |
commit | 85bb4d466efeb2540363065d7c0987a9d60f70e9 (patch) | |
tree | ea5e5aa738afb37a2d3bc4e74f9be64c15f3d188 | |
parent | 4710715102df3806479985679bd8048631ccaab5 (diff) | |
download | cru-85bb4d466efeb2540363065d7c0987a9d60f70e9.tar.gz cru-85bb4d466efeb2540363065d7c0987a9d60f70e9.tar.bz2 cru-85bb4d466efeb2540363065d7c0987a9d60f70e9.zip |
finish animation!!!
-rw-r--r-- | CruUI/CruUI.vcxproj | 1 | ||||
-rw-r--r-- | CruUI/CruUI.vcxproj.filters | 3 | ||||
-rw-r--r-- | CruUI/application.cpp | 6 | ||||
-rw-r--r-- | CruUI/application.h | 8 | ||||
-rw-r--r-- | CruUI/base.h | 71 | ||||
-rw-r--r-- | CruUI/builder.h | 42 | ||||
-rw-r--r-- | CruUI/cru_event.h | 2 | ||||
-rw-r--r-- | CruUI/debug_base.h | 10 | ||||
-rw-r--r-- | CruUI/exception.cpp | 43 | ||||
-rw-r--r-- | CruUI/exception.h | 78 | ||||
-rw-r--r-- | CruUI/graph/graph.h | 2 | ||||
-rw-r--r-- | CruUI/timer.cpp | 23 | ||||
-rw-r--r-- | CruUI/timer.h | 18 | ||||
-rw-r--r-- | CruUI/ui/animations/animation.cpp | 227 | ||||
-rw-r--r-- | CruUI/ui/animations/animation.h | 176 | ||||
-rw-r--r-- | CruUI/ui/control.cpp | 8 | ||||
-rw-r--r-- | CruUI/ui/control.h | 6 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.cpp | 15 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.h | 17 | ||||
-rw-r--r-- | CruUI/ui/controls/toggle_button.cpp | 13 | ||||
-rw-r--r-- | CruUI/ui/window.h | 1 |
21 files changed, 419 insertions, 351 deletions
diff --git a/CruUI/CruUI.vcxproj b/CruUI/CruUI.vcxproj index adc035f1..df67a297 100644 --- a/CruUI/CruUI.vcxproj +++ b/CruUI/CruUI.vcxproj @@ -162,7 +162,6 @@ <ClInclude Include="system_headers.h" /> <ClInclude Include="timer.h" /> <ClInclude Include="ui\animations\animation.h" /> - <ClInclude Include="builder.h" /> <ClInclude Include="ui\control.h" /> <ClInclude Include="global_macros.h" /> <ClInclude Include="ui\controls\linear_layout.h" /> diff --git a/CruUI/CruUI.vcxproj.filters b/CruUI/CruUI.vcxproj.filters index af6853a9..a7ea8f69 100644 --- a/CruUI/CruUI.vcxproj.filters +++ b/CruUI/CruUI.vcxproj.filters @@ -69,9 +69,6 @@ <ClInclude Include="ui\animations\animation.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="builder.h"> - <Filter>Header Files</Filter> - </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="application.cpp"> diff --git a/CruUI/application.cpp b/CruUI/application.cpp index f1d57153..78b44d7e 100644 --- a/CruUI/application.cpp +++ b/CruUI/application.cpp @@ -2,6 +2,7 @@ #include <fmt/format.h> +#include "exception.h" #include "timer.h" #include "ui/window.h" #include "graph/graph.h" @@ -96,13 +97,14 @@ namespace cru { window_manager_ = std::make_unique<ui::WindowManager>(); graph_manager_ = std::make_unique<graph::GraphManager>(); timer_manager_ = std::make_unique<TimerManager>(); - animation_manager_ = std::make_unique<ui::animations::AnimationManager>(); + animation_manager_ = std::make_unique<ui::animations::details::AnimationManager>(); god_window_ = std::make_unique<GodWindow>(this); } Application::~Application() { + animation_manager_.reset(); instance_ = nullptr; } @@ -128,6 +130,6 @@ namespace cru { auto p_action_copy = new InvokeLaterAction(std::move(action)); if (PostMessageW(Application::GetInstance()->GetGodWindow()->GetHandle(), invoke_later_message_id, reinterpret_cast<WPARAM>(p_action_copy), 0) == 0) - throw std::runtime_error(fmt::format("Last error: {}.", ::GetLastError())); + throw Win32Error(::GetLastError(), "InvokeLater failed to post message."); } } diff --git a/CruUI/application.h b/CruUI/application.h index a0229bfa..fe7422d3 100644 --- a/CruUI/application.h +++ b/CruUI/application.h @@ -15,7 +15,7 @@ namespace cru class WindowClass; class WindowManager; - namespace animations + namespace animations::details { class AnimationManager; } @@ -86,7 +86,7 @@ namespace cru return timer_manager_.get(); } - ui::animations::AnimationManager* GetAnimationManager() const + ui::animations::details::AnimationManager* GetAnimationManager() const { return animation_manager_.get(); } @@ -107,12 +107,12 @@ namespace cru std::unique_ptr<ui::WindowManager> window_manager_; std::unique_ptr<graph::GraphManager> graph_manager_; std::unique_ptr<TimerManager> timer_manager_; - std::unique_ptr<ui::animations::AnimationManager> animation_manager_; + std::unique_ptr<ui::animations::details::AnimationManager> animation_manager_; std::unique_ptr<GodWindow> god_window_; }; - using InvokeLaterAction = Action<>; + using InvokeLaterAction = Function<void()>; void InvokeLater(InvokeLaterAction&& action); } diff --git a/CruUI/base.h b/CruUI/base.h index 99b493b1..542546fb 100644 --- a/CruUI/base.h +++ b/CruUI/base.h @@ -14,11 +14,19 @@ #include <folly/Function.h> +#include <utility> +#include <type_traits> #include <stdexcept> - +#include <memory> +#include <string_view> +#include <chrono> namespace cru { + template<typename T> struct is_shared_ptr : std::false_type {}; + template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {}; + template<typename T> constexpr bool is_shared_ptr_v = is_shared_ptr<T>::value; + enum class FlowControl { Continue, @@ -28,17 +36,31 @@ namespace cru #ifdef CRU_DEBUG using String = std::wstring; #else - using String = folly::basic_fbstring<wchar_t>; + using String = folly::basic_fbstring<wchar_t>; #endif + using StringView = std::wstring_view; + template<typename FunctionType> using Function = folly::Function<FunctionType>; - template<typename... Args> - using Action = Function<void(Args...)>; + template<typename FunctionType> + using FunctionPtr = std::shared_ptr<Function<FunctionType>>; + + using Action = Function<void()>; + using ActionPtr = FunctionPtr<void()>; - template<typename... Args> - using FlowControlAction = Function<FlowControl(Args...)>; + template<typename Type, typename... Args> + Type CreatePtr(Args&&... args) + { + static_assert(is_shared_ptr_v<Type>); + return std::make_shared<typename Type::element_type>(std::forward<Args>(args)...); + } + + inline ActionPtr CreateActionPtr(Action&& action) + { + return std::make_shared<Action>(std::move(action)); + } #ifdef CRU_DEBUG template<typename T> @@ -48,24 +70,33 @@ namespace cru using Vector = folly::fbvector<T>; #endif + using FloatSecond = std::chrono::duration<double, std::chrono::seconds::period>; + class Object - { - public: - Object() = default; - Object(const Object&) = default; - Object& operator = (const Object&) = default; - Object(Object&&) = default; - Object& operator = (Object&&) = default; - virtual ~Object() = default; - }; - - struct Interface - { - virtual ~Interface() = default; - }; + { + public: + Object() = default; + Object(const Object&) = default; + Object& operator = (const Object&) = default; + Object(Object&&) = default; + Object& operator = (Object&&) = default; + virtual ~Object() = default; + }; + + struct Interface + { + virtual ~Interface() = default; + }; [[noreturn]] inline void UnreachableCode() { throw std::logic_error("Unreachable code."); } + + struct ICancelable : virtual Interface + { + virtual void Cancel() = 0; + }; + + using CancelablePtr = std::shared_ptr<ICancelable>; } diff --git a/CruUI/builder.h b/CruUI/builder.h deleted file mode 100644 index 3ae8724e..00000000 --- a/CruUI/builder.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "base.h" - -namespace cru -{ - template<typename T> - class OneTimeBuilder : public Object - { - protected: - OneTimeBuilder() = default; - - public: - OneTimeBuilder(const OneTimeBuilder& other) = delete; - OneTimeBuilder(OneTimeBuilder&& other) = delete; - OneTimeBuilder& operator=(const OneTimeBuilder& other) = delete; - OneTimeBuilder& operator=(OneTimeBuilder&& other) = delete; - virtual ~OneTimeBuilder() = default; - - T* Create() - { - if (is_valid_) - { - is_valid_ = false; - return OnCreate(); - } - else - throw std::runtime_error("OneTimeBuilder is invalid."); - } - - bool IsValid() const - { - return is_valid_; - } - - protected: - virtual T* OnCreate() = 0; - - private: - bool is_valid_ = true; - }; -} diff --git a/CruUI/cru_event.h b/CruUI/cru_event.h index f5e548c0..3a2dccfa 100644 --- a/CruUI/cru_event.h +++ b/CruUI/cru_event.h @@ -46,7 +46,7 @@ namespace cru { using ArgsType = TArgsType; - using EventHandler = Action<ArgsType&>; + using EventHandler = Function<void(ArgsType&)>; using EventHandlerPtr = std::shared_ptr<EventHandler>; Event() = default; diff --git a/CruUI/debug_base.h b/CruUI/debug_base.h index f78decbd..7669b9df 100644 --- a/CruUI/debug_base.h +++ b/CruUI/debug_base.h @@ -2,8 +2,8 @@ #include "system_headers.h" -#include <type_traits> #include <chrono> +#include <string_view> #include <fmt/format.h> #include "base.h" @@ -11,7 +11,7 @@ namespace cru::debug { #ifdef CRU_DEBUG - inline void DebugTime(Function<void()>&& action, const wchar_t* const hint_message) + inline void DebugTime(Function<void()>&& action, const StringView& hint_message) { const auto before = std::chrono::steady_clock::now(); action(); @@ -21,7 +21,7 @@ namespace cru::debug } template<typename TReturn> - TReturn DebugTime(Function<TReturn()>&& action, const wchar_t* const hint_message) + TReturn DebugTime(Function<TReturn()>&& action, const StringView& hint_message) { const auto before = std::chrono::steady_clock::now(); auto&& result = action(); @@ -31,13 +31,13 @@ namespace cru::debug return std::move(result); } #else - inline void DebugTime(Function<void()>&& action, const wchar_t* const hint_message) + inline void DebugTime(Function<void()>&& action, const StringView& hint_message) { action(); } template<typename TReturn> - TReturn DebugTime(Function<TReturn()>&& action, const wchar_t* const hint_message) + TReturn DebugTime(Function<TReturn()>&& action, const StringView& hint_message) { return action(); } diff --git a/CruUI/exception.cpp b/CruUI/exception.cpp index 45af254d..38075247 100644 --- a/CruUI/exception.cpp +++ b/CruUI/exception.cpp @@ -1,29 +1,34 @@ #include "exception.h" -#include <sstream> -#include <iomanip> +#include <fmt/format.h> namespace cru { - HResultError::HResultError(const HRESULT h_result) - : runtime_error(MakeMessage(h_result, std::nullopt)), h_result_(h_result) - { + inline std::string HResultMakeMessage(HRESULT h_result, std::optional<std::string> message) + { + if (message.has_value()) + return fmt::format("An HResultError is thrown. HRESULT: {:#08x}.\n", h_result); + else + return fmt::format("An HResultError is thrown. HRESULT: {:#08x}.\nAdditional message: {}\n", h_result, message.value()); + } - } + HResultError::HResultError(HRESULT h_result, std::optional<std::string_view> additional_message) + : runtime_error(HResultMakeMessage(h_result, std::nullopt)), h_result_(h_result) + { - HResultError::HResultError(const HRESULT h_result, const std::string& message) - : runtime_error(MakeMessage(h_result, std::make_optional(message))), h_result_(h_result) - { + } - } + inline std::string Win32MakeMessage(DWORD error_code, std::optional<std::string> message) + { + if (message.has_value()) + return fmt::format("Last error code: {:#04x}.\n", error_code); + else + return fmt::format("Last error code: {:#04x}.\nAdditional message: {}\n", error_code, message.value()); + } - std::string HResultError::MakeMessage(HRESULT h_result, std::optional<std::string> message) - { - std::stringstream ss; - ss << "An HResultError is thrown. HRESULT: 0x" << std::setfill('0') - << std::setw(sizeof h_result * 2) << std::hex << h_result << "."; - if (message.has_value()) - ss << "Additional message: " << message.value(); - return ss.str(); - } + Win32Error::Win32Error(DWORD error_code, std::optional<std::string_view> additional_message) + : runtime_error(Win32MakeMessage(error_code, std::nullopt)), error_code_(error_code) + { + + } } diff --git a/CruUI/exception.h b/CruUI/exception.h index c7d6f996..2817f261 100644 --- a/CruUI/exception.h +++ b/CruUI/exception.h @@ -2,41 +2,57 @@ #include "system_headers.h" #include <optional> +#include <string_view> #include "base.h" namespace cru { - class HResultError : public std::runtime_error - { - public: - explicit HResultError(HRESULT h_result); - HResultError(HRESULT h_result, const std::string& message); - HResultError(const HResultError& other) = default; - HResultError(HResultError&& other) = default; - HResultError& operator=(const HResultError& other) = default; - HResultError& operator=(HResultError&& other) = default; - ~HResultError() override = default; - - HRESULT GetHResult() const - { + class HResultError : public std::runtime_error + { + public: + explicit HResultError(HRESULT h_result, std::optional<std::string_view> additional_message = std::nullopt); + HResultError(const HResultError& other) = default; + HResultError(HResultError&& other) = default; + HResultError& operator=(const HResultError& other) = default; + HResultError& operator=(HResultError&& other) = default; + ~HResultError() override = default; + + HRESULT GetHResult() const + { return h_result_; - } - - private: - static std::string MakeMessage(HRESULT h_result, std::optional<std::string> message); - - private: - HRESULT h_result_; - }; - - inline void ThrowIfFailed(const HRESULT h_result) { - if (FAILED(h_result)) - throw HResultError(h_result); - } - - inline void ThrowIfFailed(const HRESULT h_result, const std::string& message) { - if (FAILED(h_result)) - throw HResultError(h_result, message); - } + } + + private: + HRESULT h_result_; + }; + + inline void ThrowIfFailed(const HRESULT h_result) { + if (FAILED(h_result)) + throw HResultError(h_result); + } + + inline void ThrowIfFailed(const HRESULT h_result, const std::string& message) { + if (FAILED(h_result)) + throw HResultError(h_result, message); + } + + class Win32Error : public std::runtime_error + { + public: + explicit Win32Error(DWORD error_code, std::optional<std::string_view> additional_message = std::nullopt); + Win32Error(const Win32Error& other) = default; + Win32Error(Win32Error&& other) = default; + Win32Error& operator=(const Win32Error& other) = default; + Win32Error& operator=(Win32Error&& other) = default; + ~Win32Error() override = default; + + HRESULT GetErrorCode() const + { + return error_code_; + } + + private: + DWORD error_code_; + }; } diff --git a/CruUI/graph/graph.h b/CruUI/graph/graph.h index fd062787..01d95797 100644 --- a/CruUI/graph/graph.h +++ b/CruUI/graph/graph.h @@ -167,7 +167,7 @@ namespace cru Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color); - inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, Action<ID2D1DeviceContext*>&& action) + inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, Function<void(ID2D1DeviceContext*)>&& action) { D2D1_MATRIX_3X2_F old_transform; device_context->GetTransform(&old_transform); diff --git a/CruUI/timer.cpp b/CruUI/timer.cpp index 7435adde..f596dde4 100644 --- a/CruUI/timer.cpp +++ b/CruUI/timer.cpp @@ -2,14 +2,14 @@ namespace cru { - UINT_PTR TimerManager::CreateTimer(const UINT milliseconds, const bool loop, std::shared_ptr<Action<>> action) + UINT_PTR TimerManager::CreateTimer(const UINT milliseconds, const bool loop, ActionPtr action) { const auto id = current_count_++; - ::SetTimer(Application::GetInstance()->GetGodWindow()->GetHandle(), 0, milliseconds, nullptr); + ::SetTimer(Application::GetInstance()->GetGodWindow()->GetHandle(), id, milliseconds, nullptr); if (loop) map_[id] = std::move(action); else - map_[id] = std::make_shared<Action<>>([this, action, id]() mutable { + map_[id] = CreateActionPtr([this, action, id]() mutable { (*action)(); this->KillTimer(id); }); @@ -26,7 +26,7 @@ namespace cru } } - std::shared_ptr<Action<>> TimerManager::GetAction(const UINT_PTR id) + ActionPtr TimerManager::GetAction(const UINT_PTR id) { const auto find_result = map_.find(id); if (find_result == map_.cend()) @@ -34,7 +34,7 @@ namespace cru return find_result->second; } - class TimerTaskImpl : public ITimerTask + class TimerTaskImpl : public virtual ICancelable { public: explicit TimerTaskImpl(UINT_PTR id); @@ -61,20 +61,15 @@ namespace cru TimerManager::GetInstance()->KillTimer(id_); } - inline UINT SecondToMillisecond(const double seconds) + TimerTask SetTimeout(std::chrono::milliseconds milliseconds, ActionPtr action) { - return static_cast<UINT>(seconds * 1000); - } - - std::shared_ptr<ITimerTask> SetTimeout(double seconds, std::shared_ptr<Action<>> action) - { - auto id = TimerManager::GetInstance()->CreateTimer(SecondToMillisecond(seconds), false, std::move(action)); + auto id = TimerManager::GetInstance()->CreateTimer(static_cast<UINT>(milliseconds.count()), false, std::move(action)); return std::make_shared<TimerTaskImpl>(id); } - std::shared_ptr<ITimerTask> SetInterval(double seconds, std::shared_ptr<Action<>> action) + TimerTask SetInterval(std::chrono::milliseconds milliseconds, ActionPtr action) { - auto id = TimerManager::GetInstance()->CreateTimer(SecondToMillisecond(seconds), true, std::move(action)); + auto id = TimerManager::GetInstance()->CreateTimer(static_cast<UINT>(milliseconds.count()), true, std::move(action)); return std::make_shared<TimerTaskImpl>(id); } } diff --git a/CruUI/timer.h b/CruUI/timer.h index 70913775..9884e46a 100644 --- a/CruUI/timer.h +++ b/CruUI/timer.h @@ -2,10 +2,9 @@ #include "system_headers.h" -#include <functional> #include <memory> #include <map> -#include <optional> +#include <chrono> #include "base.h" #include "application.h" @@ -28,20 +27,17 @@ namespace cru TimerManager& operator=(TimerManager&& other) = delete; ~TimerManager() override = default; - UINT_PTR CreateTimer(UINT milliseconds, bool loop, std::shared_ptr<Action<>> action); + UINT_PTR CreateTimer(UINT milliseconds, bool loop, ActionPtr action); void KillTimer(UINT_PTR id); - std::shared_ptr<Action<>> GetAction(UINT_PTR id); + ActionPtr GetAction(UINT_PTR id); private: - std::map<UINT_PTR, std::shared_ptr<Action<>>> map_{}; + std::map<UINT_PTR, ActionPtr> map_{}; UINT_PTR current_count_ = 0; }; - struct ITimerTask : virtual Interface - { - virtual void Cancel() = 0; - }; + using TimerTask = CancelablePtr; - std::shared_ptr<ITimerTask> SetTimeout(double seconds, std::shared_ptr<Action<>> action); - std::shared_ptr<ITimerTask> SetInterval(double seconds, std::shared_ptr<Action<>> action); + TimerTask SetTimeout(std::chrono::milliseconds milliseconds, ActionPtr action); + TimerTask SetInterval(std::chrono::milliseconds milliseconds, ActionPtr action); } diff --git a/CruUI/ui/animations/animation.cpp b/CruUI/ui/animations/animation.cpp index 26b7d5fc..9d05860a 100644 --- a/CruUI/ui/animations/animation.cpp +++ b/CruUI/ui/animations/animation.cpp @@ -5,99 +5,186 @@ namespace cru::ui::animations { - constexpr int frame_rate = 60; - constexpr double frame_step_time = 1.0 / frame_rate; - - AnimationManager::AnimationManager() - : timer_action_(new Action<>([this]() + namespace details { - for (auto& animation : animations_) + class AnimationDelegateImpl; + constexpr double frame_rate = 60; + constexpr AnimationTimeUnit frame_step_time = AnimationTimeUnit(1) / frame_rate; + + + class AnimationDelegateImpl : public virtual IAnimationDelegate { - if (animation.second->Step(frame_step_time)) - InvokeLater([=] + public: + explicit AnimationDelegateImpl(String tag) + : tag_(std::move(tag)) + { + + } + AnimationDelegateImpl(const AnimationDelegateImpl& other) = delete; + AnimationDelegateImpl(AnimationDelegateImpl&& other) = delete; + AnimationDelegateImpl& operator=(const AnimationDelegateImpl& other) = delete; + AnimationDelegateImpl& operator=(AnimationDelegateImpl&& other) = delete; + ~AnimationDelegateImpl() override = default; + + void Cancel() override + { + AnimationManager::GetInstance()->RemoveAnimation(tag_); + } + + private: + String tag_; + }; + + + class Animation : public Object + { + public: + Animation( + String tag, + AnimationTimeUnit duration, + Vector<AnimationStepHandlerPtr> step_handlers, + Vector<AnimationStartHandlerPtr> start_handlers, + Vector<ActionPtr> finish_handlers, + Vector<ActionPtr> cancel_handlers, + AnimationDelegatePtr delegate + ); + Animation(const Animation& other) = delete; + Animation(Animation&& other) = delete; + Animation& operator=(const Animation& other) = delete; + Animation& operator=(Animation&& other) = delete; + ~Animation() override; + + + // If finish or invalid, return false. + bool Step(AnimationTimeUnit time); + + String GetTag() const { - RemoveAnimation(animation.second); //TODO!!! - }); + return tag_; + } + + private: + const String tag_; + const AnimationTimeUnit duration_; + Vector<AnimationStepHandlerPtr> step_handlers_; + Vector<AnimationStartHandlerPtr> start_handlers_; + Vector<ActionPtr> finish_handlers_; + Vector<ActionPtr> cancel_handlers_; + AnimationDelegatePtr delegate_; + + AnimationTimeUnit current_time_ = AnimationTimeUnit::zero(); + }; + + AnimationManager::AnimationManager() + : timer_action_(CreateActionPtr([this]() + { + auto i = animations_.cbegin(); + while (i != animations_.cend()) + { + auto current_i = i++; + if (current_i->second->Step(frame_step_time)) + animations_.erase(current_i); + } + + if (animations_.empty()) + KillTimer(); + })) + { + } - })) - { - } + AnimationManager::~AnimationManager() + { + KillTimer(); + } - AnimationManager::~AnimationManager() - { - for (auto& animation : animations_) - delete animation.second; + AnimationDelegatePtr AnimationManager::CreateAnimation(String tag, AnimationTimeUnit duration, + Vector<AnimationStepHandlerPtr> step_handlers, Vector<AnimationStartHandlerPtr> start_handlers, + Vector<ActionPtr> finish_handlers, Vector<ActionPtr> cancel_handlers) + { + if (animations_.empty()) + SetTimer(); - if (timer_) - timer_->Cancel(); - } + auto delegate = std::make_shared<AnimationDelegateImpl>(tag); - void AnimationManager::AddAnimation(Animation* animation) - { - if (animations_.empty()) - timer_ = SetInterval(frame_step_time, timer_action_); + animations_[tag] = std::make_unique<Animation>(tag, duration, std::move(step_handlers), std::move(start_handlers), std::move(finish_handlers), std::move(cancel_handlers), delegate); - const auto find_result = animations_.find(animation->GetTag()); - if (find_result != animations_.cend()) - find_result->second->Cancel(); - animations_.insert_or_assign(animation->GetTag(), animation); - } + return delegate; + } - void AnimationManager::RemoveAnimation(Animation* animation) - { - const auto find_result = animations_.find(animation->GetTag()); - if (find_result != animations_.cend()) + void AnimationManager::RemoveAnimation(const String& tag) { - delete find_result->second; - animations_.erase(find_result); + const auto find_result = animations_.find(tag); + if (find_result != animations_.cend()) + animations_.erase(find_result); + + if (animations_.empty()) + KillTimer(); } - if (animations_.empty()) + void AnimationManager::SetTimer() { - assert(timer_); - timer_->Cancel(); - timer_ = nullptr; + if (timer_ == nullptr) + timer_ = SetInterval(std::chrono::duration_cast<std::chrono::milliseconds>(frame_step_time), timer_action_); } - } - Animation::Animation(String tag, const double duration, - const Vector<std::shared_ptr<Action<Animation*, double>>>& step_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& start_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& finish_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& cancel_handlers - ) : tag_(std::move(tag)), duration_(duration), step_handlers_(step_handlers), - start_handlers_(start_handlers), finish_handlers_(finish_handlers), cancel_handlers_(cancel_handlers) - { - AnimationManager::GetInstance()->AddAnimation(this); - } + void AnimationManager::KillTimer() + { + if (timer_ != nullptr) + { + timer_->Cancel(); + timer_ = nullptr; + } + } - bool Animation::Step(const double time) - { - current_time_ += time; - if (current_time_ > duration_) + Animation::Animation( + String tag, + AnimationTimeUnit duration, + Vector<AnimationStepHandlerPtr> step_handlers, + Vector<AnimationStartHandlerPtr> start_handlers, + Vector<ActionPtr> finish_handlers, + Vector<ActionPtr> cancel_handlers, + AnimationDelegatePtr delegate + ) : tag_(std::move(tag)), duration_(duration), + step_handlers_(std::move(step_handlers)), + start_handlers_(std::move(start_handlers)), + finish_handlers_(std::move(finish_handlers)), + cancel_handlers_(std::move(cancel_handlers)), + delegate_(std::move(delegate)) + { + + } + + Animation::~Animation() { - for (auto& handler : step_handlers_) - (*handler)(this, 1); - for (auto& handler : finish_handlers_) - (*handler)(this); - return true; + if (current_time_ < duration_) + for (auto& handler : cancel_handlers_) + (*handler)(); } - else + + bool Animation::Step(const AnimationTimeUnit time) { - for (auto& handler : step_handlers_) - (*handler)(this, current_time_ / duration_); - return false; + current_time_ += time; + if (current_time_ > duration_) + { + for (auto& handler : step_handlers_) + (*handler)(delegate_, 1); + for (auto& handler : finish_handlers_) + (*handler)(); + return true; + } + else + { + for (auto& handler : step_handlers_) + (*handler)(delegate_, current_time_ / duration_); + return false; + } } + } - void Animation::Cancel() + AnimationDelegatePtr AnimationBuilder::Start() const { - for (auto& handler : cancel_handlers_) - (*handler)(this); - InvokeLater([this] - { - AnimationManager::GetInstance()->RemoveAnimation(this); //TODO!!! - }); + return details::AnimationManager::GetInstance()->CreateAnimation(tag, duration, step_handlers_, start_handlers_, finish_handlers_, cancel_handlers_); } } diff --git a/CruUI/ui/animations/animation.h b/CruUI/ui/animations/animation.h index fb6ba93e..69b08b0c 100644 --- a/CruUI/ui/animations/animation.h +++ b/CruUI/ui/animations/animation.h @@ -1,131 +1,107 @@ #pragma once -#include <map> +#include <unordered_map> #include "base.h" #include "application.h" #include "timer.h" -#include "builder.h" namespace cru::ui::animations { - class Animation; + using AnimationTimeUnit = FloatSecond; + + using IAnimationDelegate = ICancelable; + using AnimationDelegatePtr = CancelablePtr; - class AnimationManager : public Object - { - public: - static AnimationManager* GetInstance() - { - return Application::GetInstance()->GetAnimationManager(); - } - - public: - AnimationManager(); - AnimationManager(const AnimationManager& other) = delete; - AnimationManager(AnimationManager&& other) = delete; - AnimationManager& operator=(const AnimationManager& other) = delete; - AnimationManager& operator=(AnimationManager&& other) = delete; - ~AnimationManager() override; + using AnimationStepHandlerPtr = FunctionPtr<void(AnimationDelegatePtr, double)>; + using AnimationStartHandlerPtr = FunctionPtr<void(AnimationDelegatePtr)>; - void AddAnimation(Animation* animation); - void RemoveAnimation(Animation* animation); - private: - std::map<String, Animation*> animations_; - std::shared_ptr<ITimerTask> timer_; - std::shared_ptr<Action<>> timer_action_; - }; - - class Animation : public Object + namespace details { - friend class AnimationManager; - protected: - Animation( - String tag, - double duration, - const Vector<std::shared_ptr<Action<Animation*, double>>>& step_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& start_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& finish_handlers, - const Vector<std::shared_ptr<Action<Animation*>>>& cancel_handlers - ); + class Animation; + using AnimationPtr = std::unique_ptr<Animation>; - public: - Animation(const Animation& other) = delete; - Animation(Animation&& other) = delete; - Animation& operator=(const Animation& other) = delete; - Animation& operator=(Animation&& other) = delete; - ~Animation() override = default; // The animation will never destroy by users. - - bool Step(double time); - void Cancel(); - String GetTag() const + class AnimationManager : public Object { - return tag_; - } + public: + static AnimationManager* GetInstance() + { + return Application::GetInstance()->GetAnimationManager(); + } - private: - const String tag_; - const double duration_; - Vector<std::shared_ptr<Action<Animation*, double>>> step_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> start_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> finish_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> cancel_handlers_; + public: + AnimationManager(); + AnimationManager(const AnimationManager& other) = delete; + AnimationManager(AnimationManager&& other) = delete; + AnimationManager& operator=(const AnimationManager& other) = delete; + AnimationManager& operator=(AnimationManager&& other) = delete; + ~AnimationManager() override; + + AnimationDelegatePtr CreateAnimation( + String tag, + AnimationTimeUnit duration, + Vector<AnimationStepHandlerPtr> step_handlers, + Vector<AnimationStartHandlerPtr> start_handlers, + Vector<ActionPtr> finish_handlers, + Vector<ActionPtr> cancel_handlers + ); + void RemoveAnimation(const String& tag); - double current_time_ = 0; + private: + void SetTimer(); + void KillTimer(); + private: + std::unordered_map<String, AnimationPtr> animations_; + std::shared_ptr<ICancelable> timer_; + ActionPtr timer_action_; + }; + } + + class AnimationBuilder : public Object + { public: - class Builder : public OneTimeBuilder<Animation> + AnimationBuilder(String tag, const AnimationTimeUnit duration) + : tag(std::move(tag)), duration(duration) { - public: - Builder(String tag, const double duration) - : tag(std::move(tag)), duration(duration) - { - } + } - String tag; - double duration; + String tag; + AnimationTimeUnit duration; - Builder& AddStepHandler(Action<Animation*, double>&& handler) - { - if (IsValid()) - step_handlers_.push_back(std::make_shared<Action<Animation*, double>>(std::move(handler))); - return *this; - } + AnimationBuilder& AddStepHandler(AnimationStepHandlerPtr handler) + { + step_handlers_.push_back(std::move(handler)); + return *this; + } - Builder& AddStartHandler(Action<Animation*>&& handler) - { - if (IsValid()) - start_handlers_.push_back(std::make_shared<Action<Animation*>>(std::move(handler))); - return *this; - } + AnimationBuilder& AddStartHandler(AnimationStartHandlerPtr handler) + { + start_handlers_.push_back(std::move(handler)); + return *this; + } - Builder& AddFinishHandler(Action<Animation*>&& handler) - { - if (IsValid()) - finish_handlers_.push_back(std::make_shared<Action<Animation*>>(std::move(handler))); - return *this; - } + AnimationBuilder& AddFinishHandler(ActionPtr handler) + { + finish_handlers_.push_back(std::move(handler)); + return *this; + } - Builder& AddCancelHandler(Action<Animation*>&& handler) - { - if (IsValid()) - cancel_handlers_.push_back(std::make_shared<Action<Animation*>>(std::move(handler))); - return *this; - } + AnimationBuilder& AddCancelHandler(ActionPtr handler) + { + cancel_handlers_.push_back(std::move(handler)); + return *this; + } - protected: - Animation* OnCreate() override - { - return new Animation(std::move(tag), duration, step_handlers_, start_handlers_, finish_handlers_, cancel_handlers_); - } + AnimationDelegatePtr Start() const; - private: - Vector<std::shared_ptr<Action<Animation*, double>>> step_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> start_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> finish_handlers_; - Vector<std::shared_ptr<Action<Animation*>>> cancel_handlers_; - }; + private: + Vector<AnimationStepHandlerPtr> step_handlers_; + Vector<AnimationStartHandlerPtr> start_handlers_; + Vector<ActionPtr> finish_handlers_; + Vector<ActionPtr> cancel_handlers_; }; } diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp index d2864fce..1fa7a08d 100644 --- a/CruUI/ui/control.cpp +++ b/CruUI/ui/control.cpp @@ -46,14 +46,14 @@ namespace cru { }); } - void Control::ForeachChild(Action<Control*>&& predicate) const + void Control::ForeachChild(Function<void(Control*)>&& predicate) const { if (is_container_) for (const auto child : children_) predicate(child); } - void Control::ForeachChild(FlowControlAction<Control*>&& predicate) const + void Control::ForeachChild(Function<FlowControl(Control*)>&& predicate) const { if (is_container_) for (const auto child : children_) @@ -141,7 +141,7 @@ namespace cru { return ancestor; } - void TraverseDescendantsInternal(Control* control, Action<Control*>& predicate) + void TraverseDescendantsInternal(Control* control, Function<void(Control*)>& predicate) { predicate(control); control->ForeachChild([&predicate](Control* c) { @@ -149,7 +149,7 @@ namespace cru { }); } - void Control::TraverseDescendants(Action<Control*>&& predicate) + void Control::TraverseDescendants(Function<void(Control*)>&& predicate) { if (is_container_) TraverseDescendantsInternal(this, predicate); diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h index ca2dfb84..daae1787 100644 --- a/CruUI/ui/control.h +++ b/CruUI/ui/control.h @@ -60,8 +60,8 @@ namespace cru } //Traverse the children - void ForeachChild(Action<Control*>&& predicate) const; - void ForeachChild(FlowControlAction<Control*>&& predicate) const; + void ForeachChild(Function<void(Control*)>&& predicate) const; + void ForeachChild(Function<FlowControl(Control*)>&& predicate) const; //Return a vector of all children. This function will create a //temporary copy of vector of children. If you just want to @@ -93,7 +93,7 @@ namespace cru } //Traverse the tree rooted the control including itself. - void TraverseDescendants(Action<Control*>&& predicate); + void TraverseDescendants(Function<void(Control*)>&& predicate); //*************** region: position and size *************** // Position and size part must be isolated from layout part. diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp index beb799d3..294c456b 100644 --- a/CruUI/ui/controls/text_block.cpp +++ b/CruUI/ui/controls/text_block.cpp @@ -53,6 +53,19 @@ namespace cru Repaint(); } + void TextBlock::AddTextLayoutHandler(TextLayoutHandlerPtr handler) + { + text_layout_handlers_.push_back(std::move(handler)); + } + + void TextBlock::RemoveTextLayoutHandler(const TextLayoutHandlerPtr& handler) + { + const auto find_result = std::find(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), + handler); + if (find_result != text_layout_handlers_.cend()) + text_layout_handlers_.erase(find_result); + } + void TextBlock::OnSizeChangedCore(events::SizeChangedEventArgs& args) { Control::OnSizeChangedCore(args); @@ -263,7 +276,7 @@ namespace cru &text_layout_ )); - std::for_each(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), [this](const std::shared_ptr<TextLayoutHandler>& handler) + std::for_each(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), [this](const TextLayoutHandlerPtr& handler) { (*handler)(text_layout_); }); diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h index db22e3c7..3fed2283 100644 --- a/CruUI/ui/controls/text_block.h +++ b/CruUI/ui/controls/text_block.h @@ -39,7 +39,7 @@ namespace cru class TextBlock : public Control { public: - using TextLayoutHandler = Action<Microsoft::WRL::ComPtr<IDWriteTextLayout>>; + using TextLayoutHandlerPtr = FunctionPtr<void(Microsoft::WRL::ComPtr<IDWriteTextLayout>)>; static TextBlock* Create( const String& text = L"", @@ -85,16 +85,9 @@ namespace cru void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format); - void AddTextLayoutHandler(std::shared_ptr<TextLayoutHandler> handler) - { - text_layout_handlers_.push_back(std::move(handler)); - } - void RemoveTextLayoutHandler(const std::shared_ptr<TextLayoutHandler>& handler) - { - const auto find_result = std::find(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), handler); - if (find_result != text_layout_handlers_.cend()) - text_layout_handlers_.erase(find_result); - } + void AddTextLayoutHandler(TextLayoutHandlerPtr handler); + + void RemoveTextLayoutHandler(const TextLayoutHandlerPtr& handler); protected: void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final; @@ -122,7 +115,7 @@ namespace cru Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_; Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_; - Vector<std::shared_ptr<TextLayoutHandler>> text_layout_handlers_; + Vector<TextLayoutHandlerPtr> text_layout_handlers_; bool is_selecting_ = false; unsigned mouse_down_position_ = 0; diff --git a/CruUI/ui/controls/toggle_button.cpp b/CruUI/ui/controls/toggle_button.cpp index a22cfda8..033fa9fc 100644 --- a/CruUI/ui/controls/toggle_button.cpp +++ b/CruUI/ui/controls/toggle_button.cpp @@ -8,7 +8,7 @@ namespace cru::ui::controls { using graph::CreateSolidBrush; - using animations::Animation; + using animations::AnimationBuilder; // ui length parameters of toggle button. constexpr float half_height = 15; @@ -56,15 +56,16 @@ namespace cru::ui::controls const auto previous_position = current_circle_position_; const auto delta = destination_x - current_circle_position_; - constexpr double total_time = 0.5; + constexpr auto total_time = FloatSecond(0.2); - const auto time = total_time * std::abs(delta) / (inner_circle_x * 2); + const auto time = total_time * (std::abs(delta) / (inner_circle_x * 2)); - Animation::Builder(fmt::format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time).AddStepHandler([=](Animation*, const float percentage) + AnimationBuilder(fmt::format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time) + .AddStepHandler(CreatePtr<animations::AnimationStepHandlerPtr>([=](animations::AnimationDelegatePtr, const double percentage) { - current_circle_position_ = previous_position + delta * percentage; + current_circle_position_ = static_cast<float>(previous_position + delta * percentage); Repaint(); - }).Create(); + })).Start(); OnToggleInternal(state); Repaint(); diff --git a/CruUI/ui/window.h b/CruUI/ui/window.h index 790e3c32..5addf963 100644 --- a/CruUI/ui/window.h +++ b/CruUI/ui/window.h @@ -1,7 +1,6 @@ #pragma once #include "system_headers.h" -#include <set> #include <map> #include <list> #include <memory> |