aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-05 20:54:48 +0800
committercrupest <crupest@outlook.com>2018-11-05 20:54:48 +0800
commit1dab244aaad8694ba37ef43caedd8c8ba0310c00 (patch)
treef70f6489a0f88520a0bdc095cd9713d03f83687b
parent252519effe30881825dd02e26dc41bd9cde34782 (diff)
downloadcru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.tar.gz
cru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.tar.bz2
cru-1dab244aaad8694ba37ef43caedd8c8ba0310c00.zip
...
-rw-r--r--CruUI.vcxproj1
-rw-r--r--CruUI.vcxproj.filters3
-rw-r--r--src/application.cpp17
-rw-r--r--src/application.h4
-rw-r--r--src/base.cpp21
-rw-r--r--src/base.h95
-rw-r--r--src/cru_event.h35
-rw-r--r--src/debug_base.h13
-rw-r--r--src/exception.cpp24
-rw-r--r--src/exception.h7
-rw-r--r--src/format.h107
-rw-r--r--src/global_macros.h2
-rw-r--r--src/graph/graph.h2
-rw-r--r--src/timer.cpp61
-rw-r--r--src/timer.h43
-rw-r--r--src/ui/animations/animation.cpp114
-rw-r--r--src/ui/animations/animation.h88
-rw-r--r--src/ui/border_property.cpp31
-rw-r--r--src/ui/border_property.h61
-rw-r--r--src/ui/control.cpp102
-rw-r--r--src/ui/control.h35
-rw-r--r--src/ui/controls/button.cpp30
-rw-r--r--src/ui/controls/button.h4
-rw-r--r--src/ui/controls/linear_layout.cpp50
-rw-r--r--src/ui/controls/text_box.cpp19
-rw-r--r--src/ui/controls/text_box.h3
-rw-r--r--src/ui/controls/text_control.cpp19
-rw-r--r--src/ui/controls/text_control.h9
-rw-r--r--src/ui/controls/toggle_button.cpp15
-rw-r--r--src/ui/layout_base.cpp7
-rw-r--r--src/ui/window.cpp11
-rw-r--r--src/ui/window.h2
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);
- }
}
diff --git a/src/base.h b/src/base.h
index 0a77e5b9..c8866cf6 100644
--- a/src/base.h
+++ b/src/base.h
@@ -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, &current_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_;