diff options
author | crupest <crupest@outlook.com> | 2018-11-05 20:54:48 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-11-05 20:54:48 +0800 |
commit | 1dab244aaad8694ba37ef43caedd8c8ba0310c00 (patch) | |
tree | f70f6489a0f88520a0bdc095cd9713d03f83687b | |
parent | 252519effe30881825dd02e26dc41bd9cde34782 (diff) | |
download | cru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.tar.gz cru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.tar.bz2 cru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.zip |
...
32 files changed, 477 insertions, 558 deletions
diff --git a/CruUI.vcxproj b/CruUI.vcxproj index 322dfe23..a2bca5bf 100644 --- a/CruUI.vcxproj +++ b/CruUI.vcxproj @@ -126,6 +126,7 @@ <ClCompile Include="src\ui\controls\linear_layout.cpp" /> <ClCompile Include="src\ui\controls\text_block.cpp" /> <ClCompile Include="src\ui\controls\text_box.cpp" /> + <ClInclude Include="src\format.h" /> <ClInclude Include="src\ui\border_property.h" /> <ClInclude Include="src\ui\controls\text_control.h" /> <ClCompile Include="src\ui\controls\toggle_button.cpp" /> diff --git a/CruUI.vcxproj.filters b/CruUI.vcxproj.filters index 35d4231e..2696b52c 100644 --- a/CruUI.vcxproj.filters +++ b/CruUI.vcxproj.filters @@ -143,6 +143,9 @@ <ClInclude Include="src\ui\cursor.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="src\format.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="src\application.cpp"> diff --git a/src/application.cpp b/src/application.cpp index 2adab7c6..7be56f56 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,7 +1,5 @@ #include "application.h" -#include <fmt/format.h> - #include "exception.h" #include "timer.h" #include "ui/window.h" @@ -58,17 +56,20 @@ namespace cru { { case invoke_later_message_id: { - const auto p_action = reinterpret_cast<InvokeLaterAction*>(w_param); + const auto p_action = reinterpret_cast<std::function<void()>*>(w_param); (*p_action)(); delete p_action; return 0; } case WM_TIMER: { - const auto action = application_->GetTimerManager()->GetAction(static_cast<UINT_PTR>(w_param)); - if (action) + const auto id = static_cast<UINT_PTR>(w_param); + const auto action = application_->GetTimerManager()->GetAction(id); + if (action.has_value()) { - (*action)(); + (action.value().second)(); + if (!action.value().first) + Application::GetInstance()->GetTimerManager()->KillTimer(id); return 0; } break; @@ -159,9 +160,9 @@ namespace cru { ::PostQuitMessage(quit_code); } - void InvokeLater(InvokeLaterAction&& action) { + void InvokeLater(const std::function<void()>& action) { //copy the action to a safe place - auto p_action_copy = new InvokeLaterAction(std::move(action)); + auto p_action_copy = new std::function<void()>(action); if (PostMessageW(Application::GetInstance()->GetGodWindow()->GetHandle(), invoke_later_message_id, reinterpret_cast<WPARAM>(p_action_copy), 0) == 0) throw Win32Error(::GetLastError(), "InvokeLater failed to post message."); diff --git a/src/application.h b/src/application.h index b371c8f9..530a781a 100644 --- a/src/application.h +++ b/src/application.h @@ -3,6 +3,7 @@ #include "system_headers.h" #include <memory> #include <optional> +#include <functional> #include "base.h" @@ -145,6 +146,5 @@ namespace cru }; - using InvokeLaterAction = Function<void()>; - void InvokeLater(InvokeLaterAction&& action); + void InvokeLater(const std::function<void()>& action); } diff --git a/src/base.cpp b/src/base.cpp index ce5554aa..f5868170 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -17,25 +17,4 @@ namespace cru throw Win32Error(::GetLastError(), "Failed to convert wide string to UTF-8."); return result; } - - void PropertyChangedNotifyObject::AddPropertyChangedListener(FunctionPtr<void(const StringView&)> listener) - { - listeners_.push_back(std::move(listener)); - } - - void PropertyChangedNotifyObject::RemovePropertyChangedListener(const FunctionPtr<void(const StringView&)>& listener) - { - for (auto i = listeners_.cbegin(); i != listeners_.cend(); ++i) - if (*i == listener) - { - listeners_.erase(i); - break; - } - } - - void PropertyChangedNotifyObject::RaisePropertyChangedEvent(const StringView& property_name) - { - for (const auto& listener : listeners_) - (*listener)(property_name); - } } @@ -4,23 +4,12 @@ #include "global_macros.h" -#ifdef CRU_DEBUG #include <string> -#include <vector> -#else -#include <folly/String.h> -#include <folly/FBVector.h> -#endif - -#include <folly/Function.h> - -#include <utility> #include <type_traits> #include <stdexcept> #include <memory> #include <string_view> #include <chrono> -#include <list> namespace cru { @@ -28,59 +17,23 @@ namespace cru 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, - Break - }; + template<typename T> struct type_tag {}; -#ifdef CRU_DEBUG + //typedefs using String = std::wstring; using MultiByteString = std::string; -#else - using String = folly::basic_fbstring<wchar_t>; - using MultiByteString = folly::fbstring; -#endif using StringView = std::wstring_view; using MultiByteStringView = std::string_view; - template<typename FunctionType> - using Function = folly::Function<FunctionType>; - - template<typename FunctionType> - using FunctionPtr = std::shared_ptr<Function<FunctionType>>; - - using Action = Function<void()>; - using ActionPtr = FunctionPtr<void()>; - - 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)...); - } - - template<typename Type> - FunctionPtr<Type> CreateFunctionPtr(Function<Type>&& function) - { - return std::make_shared<Function<Type>>(std::move(function)); - } + using FloatSecond = std::chrono::duration<double, std::chrono::seconds::period>; - inline ActionPtr CreateActionPtr(Action&& action) + enum class FlowControl { - return std::make_shared<Action>(std::move(action)); - } - -#ifdef CRU_DEBUG - template<typename T> - using Vector = std::vector<T>; -#else - template<typename T> - using Vector = folly::fbvector<T>; -#endif + Continue, + Break + }; - using FloatSecond = std::chrono::duration<double, std::chrono::seconds::period>; class Object { @@ -103,37 +56,11 @@ namespace cru throw std::logic_error("Unreachable code."); } - struct ICancelable : virtual Interface - { - virtual void Cancel() = 0; - }; - - using CancelablePtr = std::shared_ptr<ICancelable>; - MultiByteString ToUtf8String(const StringView& string); - - class PropertyChangedNotifyObject : public Object + inline void Require(const bool condition, const MultiByteStringView& error_message) { - public: - using PropertyChangedHandler = Function<void(const StringView&)>; - using PropertyChangedHandlerPtr = FunctionPtr<void(const StringView&)>; - - PropertyChangedNotifyObject() = default; - PropertyChangedNotifyObject(const PropertyChangedNotifyObject& other) = delete; - PropertyChangedNotifyObject(PropertyChangedNotifyObject&& other) = delete; - PropertyChangedNotifyObject& operator = (const PropertyChangedNotifyObject& other) = delete; - PropertyChangedNotifyObject& operator = (PropertyChangedNotifyObject&& other) = delete; - ~PropertyChangedNotifyObject() override = default; - - void AddPropertyChangedListener(FunctionPtr<void(const StringView&)> listener); - - void RemovePropertyChangedListener(const FunctionPtr<void(const StringView&)>& listener); - - protected: - void RaisePropertyChangedEvent(const StringView& property_name); - - private: - std::list<FunctionPtr<void(const StringView&)>> listeners_; - }; + if (!condition) + throw std::invalid_argument(error_message.data()); + } } diff --git a/src/cru_event.h b/src/cru_event.h index d0a7eb82..1103cdba 100644 --- a/src/cru_event.h +++ b/src/cru_event.h @@ -1,9 +1,8 @@ #pragma once #include <type_traits> -#include <list> -#include <memory> -#include <algorithm> +#include <functional> +#include <unordered_map> #include "base.h" @@ -46,8 +45,8 @@ namespace cru { using ArgsType = TArgsType; - using EventHandler = Function<void(ArgsType&)>; - using EventHandlerPtr = std::shared_ptr<EventHandler>; + using EventHandler = std::function<void(ArgsType&)>; + using EventHandlerToken = long; Event() = default; Event(const Event&) = delete; @@ -56,28 +55,22 @@ namespace cru { Event& operator = (Event&&) = delete; ~Event() = default; - //Create a EventHandlerPtr from the given handler, - //add it to list and return it. - EventHandlerPtr AddHandler(EventHandler&& handler) + EventHandlerToken AddHandler(const EventHandler& handler) { - EventHandlerPtr ptr = std::make_shared<EventHandler>(std::move(handler)); - handlers_.push_back(ptr); - return ptr; + const auto token = current_token_++; + handlers_.emplace(token, handler); + return token; } - void AddHandler(EventHandlerPtr handler) { - handlers_.push_back(handler); - } - - void RemoveHandler(EventHandlerPtr handler) { - auto find_result = std::find(handlers_.cbegin(), handlers_.cend(), handler); + void RemoveHandler(const EventHandlerToken token) { + auto find_result = handlers_.find(token); if (find_result != handlers_.cend()) handlers_.erase(find_result); } void Raise(ArgsType& args) { - for (auto ptr : handlers_) - (*ptr)(args); + for (const auto& handler : handlers_) + (handler.second)(args); } bool IsNoHandler() const @@ -86,6 +79,8 @@ namespace cru { } private: - std::list<EventHandlerPtr> handlers_; + std::unordered_map<EventHandlerToken, EventHandler> handlers_; + + EventHandlerToken current_token_ = 0; }; } diff --git a/src/debug_base.h b/src/debug_base.h index 7669b9df..c750ad31 100644 --- a/src/debug_base.h +++ b/src/debug_base.h @@ -2,32 +2,31 @@ #include "system_headers.h" -#include <chrono> -#include <string_view> -#include <fmt/format.h> +#include <functional> #include "base.h" +#include "format.h" namespace cru::debug { #ifdef CRU_DEBUG - inline void DebugTime(Function<void()>&& action, const StringView& hint_message) + inline void DebugTime(const std::function<void()>& action, const StringView& hint_message) { const auto before = std::chrono::steady_clock::now(); action(); const auto after = std::chrono::steady_clock::now(); const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(after - before); - OutputDebugStringW(fmt::format(L"{}: {}ms.\n", hint_message, duration.count()).c_str()); + OutputDebugStringW(Format(L"{}: {}ms.\n", hint_message, duration.count()).c_str()); } template<typename TReturn> - TReturn DebugTime(Function<TReturn()>&& action, const StringView& hint_message) + TReturn DebugTime(const std::function<TReturn()>& action, const StringView& hint_message) { const auto before = std::chrono::steady_clock::now(); auto&& result = action(); const auto after = std::chrono::steady_clock::now(); const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(after - before); - OutputDebugStringW(fmt::format(L"{}: {}ms.\n", hint_message, duration.count()).c_str()); + OutputDebugStringW(Format(L"{}: {}ms.\n", hint_message, duration.count()).c_str()); return std::move(result); } #else diff --git a/src/exception.cpp b/src/exception.cpp index a1d59ceb..92face96 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -1,32 +1,38 @@ #include "exception.h" -#include <fmt/format.h> +#include "format.h" namespace cru { - inline std::string HResultMakeMessage(HRESULT h_result, std::optional<std::string> message) + inline std::string HResultMakeMessage(HRESULT h_result, std::optional<MultiByteStringView> message) { + char buffer[10]; + sprintf_s(buffer, "%#08x", h_result); + if (message.has_value()) - return fmt::format("An HResultError is thrown. HRESULT: {:#08x}.\nAdditional message: {}\n", h_result, message.value()); + return Format("An HResultError is thrown. HRESULT: {}.\nAdditional message: {}\n", buffer, message.value()); else - return fmt::format("An HResultError is thrown. HRESULT: {:#08x}.\n", h_result); + return Format("An HResultError is thrown. HRESULT: {}.\n", buffer); } - HResultError::HResultError(HRESULT h_result, std::optional<std::string_view> additional_message) + HResultError::HResultError(HRESULT h_result, std::optional<MultiByteStringView> additional_message) : runtime_error(HResultMakeMessage(h_result, std::nullopt)), h_result_(h_result) { } - inline std::string Win32MakeMessage(DWORD error_code, std::optional<std::string> message) + inline std::string Win32MakeMessage(DWORD error_code, std::optional<MultiByteStringView> message) { + char buffer[10]; + sprintf_s(buffer, "%#04x", error_code); + if (message.has_value()) - return fmt::format("Last error code: {:#04x}.\nAdditional message: {}\n", error_code, message.value()); + return Format("Last error code: {}.\nAdditional message: {}\n", buffer, message.value()); else - return fmt::format("Last error code: {:#04x}.\n", error_code); + return Format("Last error code: {}.\n", buffer); } - Win32Error::Win32Error(DWORD error_code, std::optional<std::string_view> additional_message) + Win32Error::Win32Error(DWORD error_code, std::optional<MultiByteStringView> additional_message) : runtime_error(Win32MakeMessage(error_code, std::nullopt)), error_code_(error_code) { diff --git a/src/exception.h b/src/exception.h index 6749b684..ae9457e7 100644 --- a/src/exception.h +++ b/src/exception.h @@ -2,7 +2,6 @@ #include "system_headers.h" #include <optional> -#include <string_view> #include "base.h" @@ -11,7 +10,7 @@ namespace cru { class HResultError : public std::runtime_error { public: - explicit HResultError(HRESULT h_result, std::optional<std::string_view> additional_message = std::nullopt); + explicit HResultError(HRESULT h_result, std::optional<MultiByteStringView> additional_message = std::nullopt); HResultError(const HResultError& other) = default; HResultError(HResultError&& other) = default; HResultError& operator=(const HResultError& other) = default; @@ -32,7 +31,7 @@ namespace cru { throw HResultError(h_result); } - inline void ThrowIfFailed(const HRESULT h_result, const std::string_view& message) { + inline void ThrowIfFailed(const HRESULT h_result, const MultiByteStringView& message) { if (FAILED(h_result)) throw HResultError(h_result, message); } @@ -40,7 +39,7 @@ namespace cru { class Win32Error : public std::runtime_error { public: - explicit Win32Error(DWORD error_code, std::optional<std::string_view> additional_message = std::nullopt); + explicit Win32Error(DWORD error_code, std::optional<MultiByteStringView> additional_message = std::nullopt); Win32Error(const Win32Error& other) = default; Win32Error(Win32Error&& other) = default; Win32Error& operator=(const Win32Error& other) = default; diff --git a/src/format.h b/src/format.h new file mode 100644 index 00000000..51875938 --- /dev/null +++ b/src/format.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +namespace cru +{ + namespace details + { + constexpr StringView PlaceHolder(type_tag<String>) + { + return StringView(L"{}"); + } + + constexpr MultiByteStringView PlaceHolder(type_tag<MultiByteString>) + { + return MultiByteStringView("{}"); + } + + template<typename TString> + void FormatInternal(TString& string) + { + const auto find_result = string.find(PlaceHolder(type_tag<TString>{})); + if (find_result != TString::npos) + throw std::invalid_argument("There is more placeholders than args."); + } + + template<typename TString, typename T, typename... TRest> + void FormatInternal(TString& string, const T& arg, const TRest&... args) + { + const auto find_result = string.find(PlaceHolder(type_tag<TString>{})); + if (find_result == TString::npos) + throw std::invalid_argument("There is less placeholders than args."); + + string.replace(find_result, 2, FormatToString(arg, type_tag<TString>{})); + FormatInternal<TString>(string, args...); + } + } + + template<typename... T> + String Format(const StringView& format, const T&... args) + { + String result(format); + details::FormatInternal<String>(result, args...); + return result; + } + + template<typename... T> + MultiByteString Format(const MultiByteStringView& format, const T&... args) + { + MultiByteString result(format); + details::FormatInternal<MultiByteString>(result, args...); + return result; + } + +#define CRU_FORMAT_NUMBER(type) \ + inline String FormatToString(const type number, type_tag<String>) \ + { \ + return std::to_wstring(number); \ + } \ + inline MultiByteString FormatToString(const type number, type_tag<MultiByteString>) \ + { \ + return std::to_string(number); \ + } + + CRU_FORMAT_NUMBER(int) + CRU_FORMAT_NUMBER(short) + CRU_FORMAT_NUMBER(long) + CRU_FORMAT_NUMBER(long long) + CRU_FORMAT_NUMBER(unsigned int) + CRU_FORMAT_NUMBER(unsigned short) + CRU_FORMAT_NUMBER(unsigned long) + CRU_FORMAT_NUMBER(unsigned long long) + CRU_FORMAT_NUMBER(float) + CRU_FORMAT_NUMBER(double) + +#undef CRU_FORMAT_NUMBER + + inline StringView FormatToString(const String& string, type_tag<String>) + { + return string; + } + + inline MultiByteString FormatToString(const MultiByteString& string, type_tag<MultiByteString>) + { + return string; + } + + inline StringView FormatToString(const StringView& string, type_tag<String>) + { + return string; + } + + inline MultiByteStringView FormatToString(const MultiByteStringView& string, type_tag<MultiByteString>) + { + return string; + } + + inline StringView FormatToString(const wchar_t* string, type_tag<String>) + { + return StringView(string); + } + + inline MultiByteStringView FormatToString(const char* string, type_tag<MultiByteString>) + { + return MultiByteString(string); + } +} diff --git a/src/global_macros.h b/src/global_macros.h index 1d671e4a..eda57187 100644 --- a/src/global_macros.h +++ b/src/global_macros.h @@ -4,8 +4,6 @@ #define CRU_DEBUG #endif -#define GLOG_NO_ABBREVIATED_SEVERITIES - #ifdef CRU_DEBUG #define CRU_DEBUG_LAYOUT #endif diff --git a/src/graph/graph.h b/src/graph/graph.h index 0f1d29d1..19f060e2 100644 --- a/src/graph/graph.h +++ b/src/graph/graph.h @@ -168,7 +168,7 @@ namespace cru Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color); Microsoft::WRL::ComPtr<IDWriteTextFormat> CreateDefaultTextFormat(); - inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, Function<void(ID2D1DeviceContext*)>&& action) + inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, const std::function<void(ID2D1DeviceContext*)>& action) { D2D1_MATRIX_3X2_F old_transform; device_context->GetTransform(&old_transform); diff --git a/src/timer.cpp b/src/timer.cpp index ce800eee..174e9402 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -1,18 +1,19 @@ #include "timer.h" +#include "application.h" + namespace cru { - UINT_PTR TimerManager::CreateTimer(const UINT milliseconds, const bool loop, ActionPtr action) + inline TimerManager* GetTimerManager() + { + return Application::GetInstance()->GetTimerManager(); + } + + UINT_PTR TimerManager::CreateTimer(const UINT milliseconds, const bool loop, const TimerAction& action) { const auto id = current_count_++; ::SetTimer(Application::GetInstance()->GetGodWindow()->GetHandle(), id, milliseconds, nullptr); - if (loop) - map_[id] = std::move(action); - else - map_[id] = CreateActionPtr([this, action, id]() mutable { - (*action)(); - this->KillTimer(id); - }); + map_.emplace(id, std::make_pair(loop, action)); return id; } @@ -22,58 +23,38 @@ namespace cru if (find_result != map_.cend()) { ::KillTimer(Application::GetInstance()->GetGodWindow()->GetHandle(), id); - // When timer is killed in tick action, we need to retain the action itself until the action finishes, so InvokeLater! - InvokeLater([=] - { - map_.erase(find_result); - }); + map_.erase(find_result); } } - ActionPtr TimerManager::GetAction(const UINT_PTR id) + std::optional<std::pair<bool, TimerAction>> TimerManager::GetAction(const UINT_PTR id) { const auto find_result = map_.find(id); if (find_result == map_.cend()) - return nullptr; + return std::nullopt; return find_result->second; } - class TimerTaskImpl : public virtual ICancelable - { - public: - explicit TimerTaskImpl(UINT_PTR id); - TimerTaskImpl(const TimerTaskImpl& other) = delete; - TimerTaskImpl(TimerTaskImpl&& other) = delete; - TimerTaskImpl& operator=(const TimerTaskImpl& other) = delete; - TimerTaskImpl& operator=(TimerTaskImpl&& other) = delete; - ~TimerTaskImpl() override = default; - - void Cancel() override; - - private: - UINT_PTR id_; - }; - - TimerTaskImpl::TimerTaskImpl(const UINT_PTR id) + TimerTask::TimerTask(const UINT_PTR id) : id_(id) { } - void TimerTaskImpl::Cancel() + void TimerTask::Cancel() { - TimerManager::GetInstance()->KillTimer(id_); + GetTimerManager()->KillTimer(id_); } - TimerTask SetTimeout(std::chrono::milliseconds milliseconds, ActionPtr action) + TimerTask SetTimeout(std::chrono::milliseconds milliseconds, const TimerAction& action) { - auto id = TimerManager::GetInstance()->CreateTimer(static_cast<UINT>(milliseconds.count()), false, std::move(action)); - return std::make_shared<TimerTaskImpl>(id); + const auto id = GetTimerManager()->CreateTimer(static_cast<UINT>(milliseconds.count()), false, action); + return TimerTask(id); } - TimerTask SetInterval(std::chrono::milliseconds milliseconds, ActionPtr action) + TimerTask SetInterval(std::chrono::milliseconds milliseconds, const TimerAction& action) { - auto id = TimerManager::GetInstance()->CreateTimer(static_cast<UINT>(milliseconds.count()), true, std::move(action)); - return std::make_shared<TimerTaskImpl>(id); + const auto id = GetTimerManager()->CreateTimer(static_cast<UINT>(milliseconds.count()), true, action); + return TimerTask(id); } } diff --git a/src/timer.h b/src/timer.h index 9884e46a..0fac2cdd 100644 --- a/src/timer.h +++ b/src/timer.h @@ -2,24 +2,20 @@ #include "system_headers.h" -#include <memory> #include <map> #include <chrono> +#include <functional> +#include <optional> #include "base.h" -#include "application.h" namespace cru { + using TimerAction = std::function<void()>; + class TimerManager : public Object { public: - static TimerManager* GetInstance() - { - return Application::GetInstance()->GetTimerManager(); - } - - public: TimerManager() = default; TimerManager(const TimerManager& other) = delete; TimerManager(TimerManager&& other) = delete; @@ -27,17 +23,36 @@ namespace cru TimerManager& operator=(TimerManager&& other) = delete; ~TimerManager() override = default; - UINT_PTR CreateTimer(UINT milliseconds, bool loop, ActionPtr action); + UINT_PTR CreateTimer(UINT milliseconds, bool loop, const TimerAction& action); void KillTimer(UINT_PTR id); - ActionPtr GetAction(UINT_PTR id); + std::optional<std::pair<bool, TimerAction>> GetAction(UINT_PTR id); private: - std::map<UINT_PTR, ActionPtr> map_{}; + std::map<UINT_PTR, std::pair<bool, TimerAction>> map_{}; UINT_PTR current_count_ = 0; }; - using TimerTask = CancelablePtr; + class TimerTask + { + friend TimerTask SetTimeout(std::chrono::milliseconds milliseconds, const TimerAction& action); + friend TimerTask SetInterval(std::chrono::milliseconds milliseconds, const TimerAction& action); + + private: + explicit TimerTask(UINT_PTR id); + + public: + TimerTask(const TimerTask& other) = default; + TimerTask(TimerTask&& other) = default; + TimerTask& operator=(const TimerTask& other) = default; + TimerTask& operator=(TimerTask&& other) = default; + ~TimerTask() = default; + + void Cancel(); + + private: + UINT_PTR id_; + }; - TimerTask SetTimeout(std::chrono::milliseconds milliseconds, ActionPtr action); - TimerTask SetInterval(std::chrono::milliseconds milliseconds, ActionPtr action); + TimerTask SetTimeout(std::chrono::milliseconds milliseconds, const TimerAction& action); + TimerTask SetInterval(std::chrono::milliseconds milliseconds, const TimerAction& action); } diff --git a/src/ui/animations/animation.cpp b/src/ui/animations/animation.cpp index 9d05860a..ca0fe8bc 100644 --- a/src/ui/animations/animation.cpp +++ b/src/ui/animations/animation.cpp @@ -1,6 +1,5 @@ #include "animation.h" -#include <cassert> #include <utility> namespace cru::ui::animations @@ -39,15 +38,12 @@ namespace cru::ui::animations 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(AnimationInfo info, AnimationDelegatePtr delegate) + : info_(std::move(info)), delegate_(std::move(delegate)) + { + + } + Animation(const Animation& other) = delete; Animation(Animation&& other) = delete; Animation& operator=(const Animation& other) = delete; @@ -60,35 +56,17 @@ namespace cru::ui::animations String GetTag() const { - return tag_; + return info_.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_; + const AnimationInfo info_; + const 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(); - })) { } @@ -98,16 +76,14 @@ namespace cru::ui::animations KillTimer(); } - AnimationDelegatePtr AnimationManager::CreateAnimation(String tag, AnimationTimeUnit duration, - Vector<AnimationStepHandlerPtr> step_handlers, Vector<AnimationStartHandlerPtr> start_handlers, - Vector<ActionPtr> finish_handlers, Vector<ActionPtr> cancel_handlers) + AnimationDelegatePtr AnimationManager::CreateAnimation(AnimationInfo info) { if (animations_.empty()) SetTimer(); + const auto tag = info.tag; auto delegate = std::make_shared<AnimationDelegateImpl>(tag); - - 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); + animations_[tag] = std::make_unique<Animation>(std::move(info), delegate); return delegate; } @@ -124,67 +100,63 @@ namespace cru::ui::animations void AnimationManager::SetTimer() { - if (timer_ == nullptr) - timer_ = SetInterval(std::chrono::duration_cast<std::chrono::milliseconds>(frame_step_time), timer_action_); + if (!timer_.has_value()) + timer_ = SetInterval(std::chrono::duration_cast<std::chrono::milliseconds>(frame_step_time), [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(); + }); } void AnimationManager::KillTimer() { - if (timer_ != nullptr) + if (timer_.has_value()) { - timer_->Cancel(); - timer_ = nullptr; + timer_.value().Cancel(); + timer_ = std::nullopt; } } - 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() { - if (current_time_ < duration_) - for (auto& handler : cancel_handlers_) - (*handler)(); + if (current_time_ < info_.duration) + for (const auto& handler : info_.cancel_handlers) + handler(); } bool Animation::Step(const AnimationTimeUnit time) { current_time_ += time; - if (current_time_ > duration_) + if (current_time_ > info_.duration) { - for (auto& handler : step_handlers_) - (*handler)(delegate_, 1); - for (auto& handler : finish_handlers_) - (*handler)(); + for (const auto& handler : info_.step_handlers) + handler(delegate_, 1); + for (const auto& handler : info_.finish_handlers) + handler(); return true; } else { - for (auto& handler : step_handlers_) - (*handler)(delegate_, current_time_ / duration_); + for (const auto& handler : info_.step_handlers) + handler(delegate_, current_time_ / info_.duration); return false; } } } - AnimationDelegatePtr AnimationBuilder::Start() const + AnimationDelegatePtr AnimationBuilder::Start() { - return details::AnimationManager::GetInstance()->CreateAnimation(tag, duration, step_handlers_, start_handlers_, finish_handlers_, cancel_handlers_); + CheckValid(); + valid_ = false; + return details::AnimationManager::GetInstance()->CreateAnimation(std::move(info_)); } } diff --git a/src/ui/animations/animation.h b/src/ui/animations/animation.h index 69b08b0c..91a666c9 100644 --- a/src/ui/animations/animation.h +++ b/src/ui/animations/animation.h @@ -10,19 +10,46 @@ namespace cru::ui::animations { using AnimationTimeUnit = FloatSecond; - - using IAnimationDelegate = ICancelable; - using AnimationDelegatePtr = CancelablePtr; + struct IAnimationDelegate : virtual Interface + { + virtual void Cancel() = 0; + }; - using AnimationStepHandlerPtr = FunctionPtr<void(AnimationDelegatePtr, double)>; - using AnimationStartHandlerPtr = FunctionPtr<void(AnimationDelegatePtr)>; + using AnimationDelegatePtr = std::shared_ptr<IAnimationDelegate>; + using AnimationStepHandler = std::function<void(AnimationDelegatePtr, double)>; + using AnimationStartHandler = std::function<void(AnimationDelegatePtr)>; + using AnimationFinishHandler = std::function<void()>; + using AnimationCancelHandler = std::function<void()>; namespace details { class Animation; using AnimationPtr = std::unique_ptr<Animation>; + class AnimationInfo + { + public: + AnimationInfo(String tag, const AnimationTimeUnit duration) + : tag(std::move(tag)), + duration(duration) + { + + } + AnimationInfo(const AnimationInfo& other) = default; + AnimationInfo(AnimationInfo&& other) = default; + AnimationInfo& operator=(const AnimationInfo& other) = default; + AnimationInfo& operator=(AnimationInfo&& other) = default; + ~AnimationInfo() = default; + + String tag; + AnimationTimeUnit duration; + std::vector<AnimationStepHandler> step_handlers{}; + std::vector<AnimationStartHandler> start_handlers{}; + std::vector<AnimationFinishHandler> finish_handlers{}; + std::vector<AnimationCancelHandler> cancel_handlers{}; + }; + class AnimationManager : public Object { public: @@ -39,14 +66,7 @@ namespace cru::ui::animations 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 - ); + AnimationDelegatePtr CreateAnimation(AnimationInfo info); void RemoveAnimation(const String& tag); private: @@ -55,8 +75,7 @@ namespace cru::ui::animations private: std::unordered_map<String, AnimationPtr> animations_; - std::shared_ptr<ICancelable> timer_; - ActionPtr timer_action_; + std::optional<TimerTask> timer_; }; } @@ -64,44 +83,49 @@ namespace cru::ui::animations { public: AnimationBuilder(String tag, const AnimationTimeUnit duration) - : tag(std::move(tag)), duration(duration) + : info_(std::move(tag), duration) { } - String tag; - AnimationTimeUnit duration; - - AnimationBuilder& AddStepHandler(AnimationStepHandlerPtr handler) + AnimationBuilder& AddStepHandler(const AnimationStepHandler& handler) { - step_handlers_.push_back(std::move(handler)); + CheckValid(); + info_.step_handlers.push_back(handler); return *this; } - AnimationBuilder& AddStartHandler(AnimationStartHandlerPtr handler) + AnimationBuilder& AddStartHandler(const AnimationStartHandler& handler) { - start_handlers_.push_back(std::move(handler)); + CheckValid(); + info_.start_handlers.push_back(handler); return *this; } - AnimationBuilder& AddFinishHandler(ActionPtr handler) + AnimationBuilder& AddFinishHandler(const AnimationFinishHandler& handler) { - finish_handlers_.push_back(std::move(handler)); + CheckValid(); + info_.finish_handlers.push_back(handler); return *this; } - AnimationBuilder& AddCancelHandler(ActionPtr handler) + AnimationBuilder& AddCancelHandler(const AnimationCancelHandler& handler) { - cancel_handlers_.push_back(std::move(handler)); + CheckValid(); + info_.cancel_handlers.push_back(handler); return *this; } - AnimationDelegatePtr Start() const; + AnimationDelegatePtr Start(); private: - Vector<AnimationStepHandlerPtr> step_handlers_; - Vector<AnimationStartHandlerPtr> start_handlers_; - Vector<ActionPtr> finish_handlers_; - Vector<ActionPtr> cancel_handlers_; + void CheckValid() const + { + if (!valid_) + throw std::runtime_error("The animation builder is invalid."); + } + + bool valid_ = true; + details::AnimationInfo info_; }; } diff --git a/src/ui/border_property.cpp b/src/ui/border_property.cpp index 03cae16e..f716a8be 100644 --- a/src/ui/border_property.cpp +++ b/src/ui/border_property.cpp @@ -4,40 +4,13 @@ namespace cru::ui { - BorderProperty::BorderProperty() + BorderProperty::BorderProperty(): BorderProperty(graph::CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black))) { - brush_ = graph::CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)); - } - - void BorderProperty::SetBrush(Microsoft::WRL::ComPtr<ID2D1Brush> brush) - { - if (brush == nullptr) - throw std::invalid_argument("Brush of BorderProperty mustn't be null."); - brush_ = std::move(brush); - RaisePropertyChangedEvent(brush_property_name); - } - - void BorderProperty::SetWidth(const float width) - { - stroke_width_ = width; - RaisePropertyChangedEvent(width_property_name); - } - void BorderProperty::SetStrokeStyle(Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style) - { - stroke_style_ = std::move(stroke_style); - RaisePropertyChangedEvent(stroke_style_property_name); } - void BorderProperty::SetRadiusX(const float radius_x) + BorderProperty::BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush): brush_(std::move(brush)) { - radius_x_ = radius_x; - RaisePropertyChangedEvent(radius_x_property_name); - } - void BorderProperty::SetRadiusY(const float radius_y) - { - radius_y_ = radius_y; - RaisePropertyChangedEvent(radius_y_property_name); } } diff --git a/src/ui/border_property.h b/src/ui/border_property.h index 71ec0e7d..ce16dea7 100644 --- a/src/ui/border_property.h +++ b/src/ui/border_property.h @@ -7,28 +7,16 @@ namespace cru::ui { - class BorderProperty final : public PropertyChangedNotifyObject + class BorderProperty final { public: - constexpr static auto brush_property_name = L"Brush"; - constexpr static auto width_property_name = L"StrokeWidth"; - constexpr static auto stroke_style_property_name = L"StrokeStyle"; - constexpr static auto radius_x_property_name = L"RadiusX"; - constexpr static auto radius_y_property_name = L"RadiusY"; - - using Ptr = std::shared_ptr<BorderProperty>; - - static Ptr Create() - { - return std::make_shared<BorderProperty>(); - } - BorderProperty(); - BorderProperty(const BorderProperty& other) = delete; - BorderProperty(BorderProperty&& other) = delete; - BorderProperty& operator=(const BorderProperty& other) = delete; - BorderProperty& operator=(BorderProperty&& other) = delete; - ~BorderProperty() override = default; + explicit BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush); + BorderProperty(const BorderProperty& other) = default; + BorderProperty(BorderProperty&& other) = default; + BorderProperty& operator=(const BorderProperty& other) = default; + BorderProperty& operator=(BorderProperty&& other) = default; + ~BorderProperty() = default; Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const @@ -56,14 +44,37 @@ namespace cru::ui return radius_y_; } - void SetBrush(Microsoft::WRL::ComPtr<ID2D1Brush> brush); - void SetWidth(float width); - void SetStrokeStyle(Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style); - void SetRadiusX(float radius_x); - void SetRadiusY(float radius_y); + void SetBrush(Microsoft::WRL::ComPtr<ID2D1Brush> brush) + { + Require(brush == nullptr, "Brush of BorderProperty mustn't be null."); + brush_ = std::move(brush); + } + + void SetStrokeWidth(const float stroke_width) + { + Require(stroke_width >= 0.0f, "Stroke width must be no less than 0."); + stroke_width_ = stroke_width; + } + + void SetStrokeStyle(Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style) + { + stroke_style_ = std::move(stroke_style); + } + + void SetRadiusX(const float radius_x) + { + Require(radius_x >= 0.0f, "Radius-x must be no less than 0."); + radius_x_ = radius_x; + } + + void SetRadiusY(const float radius_y) + { + Require(radius_y >= 0.0f, "Radius-y must be no less than 0."); + radius_y_ = radius_y; + } private: - Microsoft::WRL::ComPtr<ID2D1Brush> brush_ = nullptr; + Microsoft::WRL::ComPtr<ID2D1Brush> brush_; float stroke_width_ = 1.0f; Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style_ = nullptr; float radius_x_ = 0.0f; diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 838747bc..37e6d2b8 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -1,5 +1,7 @@ #include "control.h" +#include <algorithm> + #include "window.h" #include "graph/graph.h" #include "exception.h" @@ -9,13 +11,7 @@ namespace cru { using namespace events; Control::Control(const bool container) : - is_container_(container), - border_property_changed_listener_(CreatePtr<PropertyChangedNotifyObject::PropertyChangedHandlerPtr>([this](const StringView& property_name) - { - if (property_name == BorderProperty::width_property_name) - InvalidateLayout(); - Repaint(); - })) + is_container_(container) { } @@ -27,27 +23,10 @@ namespace cru { Control::~Control() { - ForeachChild([](auto control) + for (auto control: GetChildren()) { delete control; - }); - } - - void Control::ForeachChild(Function<void(Control*)>&& predicate) const - { - if (is_container_) - for (const auto child : children_) - predicate(child); - } - - void Control::ForeachChild(Function<FlowControl(Control*)>&& predicate) const - { - if (is_container_) - for (const auto child : children_) - { - if (predicate(child) == FlowControl::Break) - break; - } + } } void AddChildCheck(Control* control) @@ -59,6 +38,11 @@ namespace cru { throw std::invalid_argument("Can't add a window as child."); } + const std::vector<Control*>& Control::GetChildren() const + { + return children_; + } + void Control::AddChild(Control* control) { ThrowIfNotContainer(); @@ -128,15 +112,17 @@ namespace cru { return ancestor; } - void TraverseDescendantsInternal(Control* control, Function<void(Control*)>& predicate) + void TraverseDescendantsInternal(Control* control, const std::function<void(Control*)>& predicate) { predicate(control); - control->ForeachChild([&predicate](Control* c) { - TraverseDescendantsInternal(c, predicate); - }); + if (control->IsContainer()) + for (auto c: control->GetChildren()) + { + TraverseDescendantsInternal(c, predicate); + } } - void Control::TraverseDescendants(Function<void(Control*)>&& predicate) + void Control::TraverseDescendants(const std::function<void(Control*)>& predicate) { if (is_container_) TraverseDescendantsInternal(this, predicate); @@ -305,13 +291,13 @@ namespace cru { return result; if (is_bordered_) - Shrink(result, Thickness(border_property_->GetStrokeWidth() / 2.0f)); + Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f)); if (range == RectRange::HalfBorder) return result; if (is_bordered_) - Shrink(result, Thickness(border_property_->GetStrokeWidth() / 2.0f)); + Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f)); if (range == RectRange::Padding) return result; @@ -321,15 +307,8 @@ namespace cru { return result; } - void Control::SetBorderProperty(BorderProperty::Ptr border_property) + void Control::InvalidateBorder() { - if (border_property == nullptr) - throw std::invalid_argument("Border property mustn't be null."); - - if (border_property_ != nullptr) - border_property_->RemovePropertyChangedListener(border_property_changed_listener_); - border_property_ = std::move(border_property); - border_property_->AddPropertyChangedListener(border_property_changed_listener_); InvalidateLayout(); Repaint(); } @@ -338,28 +317,11 @@ namespace cru { { if (bordered != is_bordered_) { - if (bordered && border_property_ == nullptr) // create border property. - { - border_property_ = BorderProperty::Create(); - border_property_->AddPropertyChangedListener(border_property_changed_listener_); - } - is_bordered_ = bordered; - InvalidateLayout(); - Repaint(); + InvalidateBorder(); } } - void Control::SetCursor(const Cursor::Ptr& cursor) - { - - } - - Cursor::Ptr Control::GetCursorInherit() - { - - } - void Control::OnAddChild(Control* child) { if (auto window = GetWindow()) @@ -419,12 +381,12 @@ namespace cru { device_context->DrawRoundedRectangle( D2D1::RoundedRect( Convert(border_rect), - border_property_->GetRadiusX(), - border_property_->GetRadiusY() + GetBorderProperty().GetRadiusX(), + GetBorderProperty().GetRadiusY() ), - border_property_->GetBrush().Get(), - border_property_->GetStrokeWidth(), - border_property_->GetStrokeStyle().Get() + GetBorderProperty().GetBrush().Get(), + GetBorderProperty().GetStrokeWidth(), + GetBorderProperty().GetStrokeStyle().Get() ); } } @@ -713,7 +675,7 @@ namespace cru { auto border_size = Size::Zero(); if (is_bordered_) { - const auto border_width = border_property_->GetStrokeWidth(); + const auto border_width = GetBorderProperty().GetStrokeWidth(); border_size = Size(border_width * 2.0f, border_width * 2.0f); } @@ -777,7 +739,7 @@ namespace cru { auto border_width = 0.0f; if (is_bordered_) { - border_width = border_property_->GetStrokeWidth(); + border_width = GetBorderProperty().GetStrokeWidth(); } const Rect content_rect( @@ -793,7 +755,7 @@ namespace cru { Size Control::OnMeasureContent(const Size& available_size) { auto max_child_size = Size::Zero(); - ForeachChild([&max_child_size, available_size](Control* control) + for (auto control: GetChildren()) { control->Measure(available_size); const auto&& size = control->GetDesiredSize(); @@ -801,13 +763,13 @@ namespace cru { max_child_size.width = size.width; if (max_child_size.height < size.height) max_child_size.height = size.height; - }); + } return max_child_size; } void Control::OnLayoutContent(const Rect& rect) { - ForeachChild([rect](Control* control) + for (auto control: GetChildren()) { const auto layout_params = control->GetLayoutParams(); const auto size = control->GetDesiredSize(); @@ -831,7 +793,7 @@ namespace cru { calculate_anchor(rect.left, layout_params->width.alignment, rect.width, size.width), calculate_anchor(rect.top, layout_params->height.alignment, rect.height, size.height) ), size)); - }); + } } void Control::CheckAndNotifyPositionChanged() diff --git a/src/ui/control.h b/src/ui/control.h index e88228d0..25cd5c0a 100644 --- a/src/ui/control.h +++ b/src/ui/control.h @@ -5,9 +5,9 @@ #include <any> #include <typeinfo> #include <utility> -#include <fmt/format.h> #include "base.h" +#include "format.h" #include "ui_base.h" #include "layout_base.h" #include "events/ui_event.h" @@ -63,6 +63,8 @@ namespace cru public: //*************** region: tree *************** + //TODO! + //virtual StringView GetControlType() const = 0; bool IsContainer() const { @@ -75,17 +77,8 @@ namespace cru return parent_; } - //Traverse the children - 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 - //traverse all children, just call ForeachChild. - Vector<Control*> GetChildren() const - { - return children_; - } + //Return a immutable vector of all children. + const std::vector<Control*>& GetChildren() const; //Add a child at tail. void AddChild(Control* control); @@ -109,7 +102,7 @@ namespace cru } //Traverse the tree rooted the control including itself. - void TraverseDescendants(Function<void(Control*)>&& predicate); + void TraverseDescendants(const std::function<void(Control*)>& predicate); //*************** region: position and size *************** // Position and size part must be isolated from layout part. @@ -187,12 +180,12 @@ namespace cru //*************** region: border *************** - BorderProperty::Ptr GetBorderProperty() const + BorderProperty& GetBorderProperty() { return border_property_; } - void SetBorderProperty(BorderProperty::Ptr border_property); + void InvalidateBorder(); bool IsBordered() const { @@ -216,7 +209,7 @@ namespace cru } catch (const std::bad_any_cast&) { - throw std::runtime_error(fmt::format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name())); + throw std::runtime_error(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name())); } } @@ -234,6 +227,8 @@ namespace cru //*************** region: cursor *************** + //TODO! + /* Cursor::Ptr GetCursor() const { return cursor_; @@ -242,6 +237,7 @@ namespace cru void SetCursor(const Cursor::Ptr& cursor); Cursor::Ptr GetCursorInherit(); + */ //*************** region: events *************** @@ -380,7 +376,7 @@ namespace cru private: Control * parent_ = nullptr; - Vector<Control*> children_{}; + std::vector<Control*> children_{}; // When position is changed and notification hasn't been // sent, it will be the old position. When position is changed @@ -406,8 +402,7 @@ namespace cru Size desired_size_ = Size::Zero(); bool is_bordered_ = false; - BorderProperty::Ptr border_property_; - PropertyChangedNotifyObject::PropertyChangedHandlerPtr border_property_changed_listener_; + BorderProperty border_property_; std::unordered_map<String, std::any> additional_properties_{}; @@ -461,6 +456,6 @@ namespace cru return control; } - constexpr std::initializer_list<Control*> ControlList(std::initializer_list<Control*> &&li) { return li; } + using ControlList = std::initializer_list<Control*>; } } diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index db0b71c2..e600eb89 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -6,33 +6,31 @@ namespace cru::ui::controls { using graph::CreateSolidBrush; - Button::Button() : Control(true) + Button::Button() : Control(true), + normal_border_{CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::RoyalBlue))}, + pressed_border_{CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Blue))} { - normal_border_ = BorderProperty::Create(); - normal_border_->SetBrush(CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::RoyalBlue))); - normal_border_->SetWidth(2); - normal_border_->SetRadiusX(6); - normal_border_->SetRadiusY(6); + normal_border_.SetStrokeWidth(2); + normal_border_.SetRadiusX(6); + normal_border_.SetRadiusY(6); - pressed_border_ = BorderProperty::Create(); - pressed_border_->SetBrush(CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Blue))); - pressed_border_->SetWidth(2); - pressed_border_->SetRadiusX(6); - pressed_border_->SetRadiusY(6); + pressed_border_.SetStrokeWidth(2); + pressed_border_.SetRadiusX(6); + pressed_border_.SetRadiusY(6); SetBordered(true); - SetBorderProperty(normal_border_); + GetBorderProperty() = normal_border_; } void Button::OnMouseClickBegin(MouseButton button) { - SetBorderProperty(pressed_border_); - Repaint(); + GetBorderProperty() = pressed_border_; + InvalidateBorder(); } void Button::OnMouseClickEnd(MouseButton button) { - SetBorderProperty(normal_border_); - Repaint(); + GetBorderProperty() = normal_border_; + InvalidateBorder(); } } diff --git a/src/ui/controls/button.h b/src/ui/controls/button.h index 011f97d2..e0ece85a 100644 --- a/src/ui/controls/button.h +++ b/src/ui/controls/button.h @@ -32,7 +32,7 @@ namespace cru::ui::controls void OnMouseClickEnd(MouseButton button) override final; private: - BorderProperty::Ptr normal_border_; - BorderProperty::Ptr pressed_border_; + BorderProperty normal_border_; + BorderProperty pressed_border_; }; } diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp index 7921745a..fb5d3db7 100644 --- a/src/ui/controls/linear_layout.cpp +++ b/src/ui/controls/linear_layout.cpp @@ -1,5 +1,7 @@ #include "linear_layout.h" +#include <algorithm> + namespace cru::ui::controls { LinearLayout::LinearLayout(const Orientation orientation) @@ -28,33 +30,33 @@ namespace cru::ui::controls // First measure Content and Exactly and count Stretch. if (orientation_ == Orientation::Horizontal) - ForeachChild([&](Control* const control) - { - const auto mode = control->GetLayoutParams()->width.mode; - if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) + for(auto control: GetChildren()) { - control->Measure(AtLeast0(rest_available_size_for_children)); - const auto size = control->GetDesiredSize(); - rest_available_size_for_children.width -= size.width; - secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length); + const auto mode = control->GetLayoutParams()->width.mode; + if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) + { + control->Measure(AtLeast0(rest_available_size_for_children)); + const auto size = control->GetDesiredSize(); + rest_available_size_for_children.width -= size.width; + secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length); + } + else + stretch_control_list.push_back(control); } - else - stretch_control_list.push_back(control); - }); else - ForeachChild([&](Control* const control) - { - const auto mode = control->GetLayoutParams()->height.mode; - if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) + for(auto control: GetChildren()) { - control->Measure(AtLeast0(rest_available_size_for_children)); - const auto size = control->GetDesiredSize(); - rest_available_size_for_children.height -= size.height; - secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length); + const auto mode = control->GetLayoutParams()->height.mode; + if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) + { + control->Measure(AtLeast0(rest_available_size_for_children)); + const auto size = control->GetDesiredSize(); + rest_available_size_for_children.height -= size.height; + secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length); + } + else + stretch_control_list.push_back(control); } - else - stretch_control_list.push_back(control); - }); if (orientation_ == Orientation::Horizontal) { @@ -97,7 +99,7 @@ namespace cru::ui::controls void LinearLayout::OnLayoutContent(const Rect& rect) { float current_main_side_anchor = 0; - ForeachChild([this, ¤t_main_side_anchor, rect](Control* control) + for(auto control: GetChildren()) { const auto layout_params = control->GetLayoutParams(); const auto size = control->GetDesiredSize(); @@ -133,6 +135,6 @@ namespace cru::ui::controls control->Layout(calculate_rect(calculate_secondary_side_anchor(rect.width, size.width), current_main_side_anchor)); current_main_side_anchor += size.height; } - }); + } } } diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp index 54b2f7ab..d6c3d132 100644 --- a/src/ui/controls/text_box.cpp +++ b/src/ui/controls/text_box.cpp @@ -1,6 +1,7 @@ #include "text_box.h" #include <cwctype> +#include <cassert> #include "graph/graph.h" #include "exception.h" @@ -21,12 +22,6 @@ namespace cru::ui::controls caret_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)); - caret_action_ = CreateActionPtr([this] - { - is_caret_show_ = !is_caret_show_; - Repaint(); - }); - SetBordered(true); } @@ -48,17 +43,21 @@ namespace cru::ui::controls void TextBox::OnGetFocusCore(events::FocusChangeEventArgs& args) { TextControl::OnGetFocusCore(args); - assert(caret_timer_ == nullptr); + assert(!caret_timer_.has_value()); is_caret_show_ = true; - caret_timer_ = SetInterval(Application::GetInstance()->GetCaretInfo().caret_blink_duration, caret_action_); + caret_timer_ = SetInterval(Application::GetInstance()->GetCaretInfo().caret_blink_duration, [this] + { + is_caret_show_ = !is_caret_show_; + Repaint(); + }); } void TextBox::OnLoseFocusCore(events::FocusChangeEventArgs& args) { Control::OnLoseFocusCore(args); - assert(caret_timer_ != nullptr); + assert(caret_timer_.has_value()); caret_timer_->Cancel(); - caret_timer_ = nullptr; + caret_timer_ = std::nullopt; is_caret_show_ = false; } diff --git a/src/ui/controls/text_box.h b/src/ui/controls/text_box.h index 37e04835..a2f4e6e8 100644 --- a/src/ui/controls/text_box.h +++ b/src/ui/controls/text_box.h @@ -46,8 +46,7 @@ namespace cru::ui::controls private: unsigned caret_position_ = 0; - TimerTask caret_timer_; - ActionPtr caret_action_; + std::optional<TimerTask> caret_timer_{}; Microsoft::WRL::ComPtr<ID2D1Brush> caret_brush_; bool is_caret_show_ = false; }; diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp index 3c5d7c33..5769af58 100644 --- a/src/ui/controls/text_control.cpp +++ b/src/ui/controls/text_control.cpp @@ -3,6 +3,7 @@ #include "ui/window.h" #include "graph/graph.h" #include "exception.h" +#include <cassert> namespace cru::ui::controls { @@ -49,19 +50,6 @@ namespace cru::ui::controls Repaint(); } - void TextControl::AddTextLayoutHandler(TextLayoutHandlerPtr handler) - { - text_layout_handlers_.push_back(std::move(handler)); - } - - void TextControl::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 TextControl::SetSelectable(const bool is_selectable) { if (!is_selectable) @@ -115,7 +103,7 @@ namespace cru::ui::controls ThrowIfFailed(layout->GetMetrics(&text_metrics)); const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth; - Vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count); + std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count); UINT32 actual_count; layout->HitTestTextRange( range.value().position, range.value().count, @@ -238,8 +226,5 @@ namespace cru::ui::controls size.width, size.height, &text_layout_ )); - - for (const auto& handler : text_layout_handlers_) - (*handler)(text_layout_); } } diff --git a/src/ui/controls/text_control.h b/src/ui/controls/text_control.h index 01bb5565..18a258f2 100644 --- a/src/ui/controls/text_control.h +++ b/src/ui/controls/text_control.h @@ -12,8 +12,6 @@ namespace cru::ui::controls const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush ); public: - using TextLayoutHandlerPtr = FunctionPtr<void(Microsoft::WRL::ComPtr<IDWriteTextLayout>)>; - TextControl(const TextControl& other) = delete; TextControl(TextControl&& other) = delete; TextControl& operator=(const TextControl& other) = delete; @@ -41,11 +39,6 @@ namespace cru::ui::controls void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format); - - void AddTextLayoutHandler(TextLayoutHandlerPtr handler); - - void RemoveTextLayoutHandler(const TextLayoutHandlerPtr& handler); - bool IsSelectable() const { return is_selectable_; @@ -96,8 +89,6 @@ namespace cru::ui::controls Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_; private: - Vector<TextLayoutHandlerPtr> text_layout_handlers_; - bool is_selectable_ = false; bool is_selecting_ = false; diff --git a/src/ui/controls/toggle_button.cpp b/src/ui/controls/toggle_button.cpp index 3cd5d3ef..c0244bb6 100644 --- a/src/ui/controls/toggle_button.cpp +++ b/src/ui/controls/toggle_button.cpp @@ -1,7 +1,5 @@ #include "toggle_button.h" -#include <fmt/format.h> - #include "graph/graph.h" #include "ui/animations/animation.h" @@ -61,12 +59,13 @@ namespace cru::ui::controls const auto time = total_time * (std::abs(delta) / (inner_circle_x * 2)); // ReSharper disable once CppExpressionWithoutSideEffects - AnimationBuilder(fmt::format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time) - .AddStepHandler(CreatePtr<animations::AnimationStepHandlerPtr>([=](animations::AnimationDelegatePtr, const double percentage) - { - current_circle_position_ = static_cast<float>(previous_position + delta * percentage); - Repaint(); - })).Start(); + AnimationBuilder(Format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time) + .AddStepHandler([=](auto, const double percentage) + { + current_circle_position_ = static_cast<float>(previous_position + delta * percentage); + Repaint(); + }) + .Start(); RaiseToggleEvent(state); Repaint(); diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp index 40c7a724..0ffe3870 100644 --- a/src/ui/layout_base.cpp +++ b/src/ui/layout_base.cpp @@ -87,13 +87,14 @@ namespace cru::ui void LayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute) { const auto position = control->GetPositionRelative(); - Point lefttop( + const Point lefttop( parent_lefttop_absolute.x + position.x, parent_lefttop_absolute.y + position.y ); control->position_cache_.lefttop_position_absolute = lefttop; - control->ForeachChild([lefttop](Control* c) { + for(auto c : control->GetChildren()) + { RefreshControlPositionCacheInternal(c, lefttop); - }); + } } } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 8889e032..323a4307 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -1,7 +1,5 @@ #include "window.h" -#include <fmt/format.h> - #include "application.h" #include "graph/graph.h" #include "exception.h" @@ -77,9 +75,9 @@ namespace cru return find_result->second; } - Vector<Window*> WindowManager::GetAllWindows() const + std::vector<Window*> WindowManager::GetAllWindows() const { - Vector<Window*> windows; + std::vector<Window*> windows; for (auto [key, value] : window_map_) windows.push_back(value); return windows; @@ -464,11 +462,10 @@ namespace cru Size Window::OnMeasureContent(const Size& available_size) { - ForeachChild([available_size](Control* control) + for (auto control: GetChildren()) { control->Measure(available_size); - }); - + } return available_size; } diff --git a/src/ui/window.h b/src/ui/window.h index e4e89776..15b3db57 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -70,7 +70,7 @@ namespace cru { //Return a pointer to the Window object related to the HWND or nullptr if the hwnd is not in the map. Window* FromHandle(HWND hwnd); - Vector<Window*> GetAllWindows() const; + std::vector<Window*> GetAllWindows() const; private: std::unique_ptr<WindowClass> general_window_class_; |