diff options
author | crupest <crupest@outlook.com> | 2019-03-31 17:14:47 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-03-31 17:14:47 +0800 |
commit | fbfd90255731954fb80483f4ba7188d3611fafec (patch) | |
tree | 8e3283c911d7aec76130d6a1dc7f5d8a85512b59 /include/cru | |
parent | 877f65e2e2c40eecc7cfeb194dc9d391af60711b (diff) | |
download | cru-fbfd90255731954fb80483f4ba7188d3611fafec.tar.gz cru-fbfd90255731954fb80483f4ba7188d3611fafec.tar.bz2 cru-fbfd90255731954fb80483f4ba7188d3611fafec.zip |
...
Diffstat (limited to 'include/cru')
-rw-r--r-- | include/cru/common/base.hpp | 18 | ||||
-rw-r--r-- | include/cru/common/format.hpp | 104 | ||||
-rw-r--r-- | include/cru/common/pre_config.hpp | 5 | ||||
-rw-r--r-- | include/cru/common/ui_base.hpp | 233 | ||||
-rw-r--r-- | include/cru/platform/debug.hpp | 8 | ||||
-rw-r--r-- | include/cru/platform/native_window.hpp | 31 | ||||
-rw-r--r-- | include/cru/platform/ui_applicaition.hpp | 28 | ||||
-rw-r--r-- | include/cru/platform/win/exception.hpp | 49 | ||||
-rw-r--r-- | include/cru/platform/win/god_window.hpp | 33 | ||||
-rw-r--r-- | include/cru/platform/win/win_application.hpp | 53 | ||||
-rw-r--r-- | include/cru/platform/win/win_pre_config.hpp | 6 | ||||
-rw-r--r-- | include/cru/platform/win/window_class.hpp | 26 |
12 files changed, 594 insertions, 0 deletions
diff --git a/include/cru/common/base.hpp b/include/cru/common/base.hpp new file mode 100644 index 00000000..7dfe8240 --- /dev/null +++ b/include/cru/common/base.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "pre_config.hpp" + +namespace cru { +class Object { + public: + Object() = default; + Object(const Object&) = default; + Object& operator=(const Object&) = default; + Object(Object&&) = default; + Object& operator=(Object&&) = default; + virtual ~Object() = default; +}; + +struct Interface { + virtual ~Interface() = default; +}; +} // namespace cru diff --git a/include/cru/common/format.hpp b/include/cru/common/format.hpp new file mode 100644 index 00000000..1fb6863a --- /dev/null +++ b/include/cru/common/format.hpp @@ -0,0 +1,104 @@ +#pragma once +#include "pre_config.hpp" + +#include <string> +#include <string_view> + +namespace cru::util { +namespace details { +template <typename T> +struct TypeTag {}; + +constexpr std::wstring_view PlaceHolder(TypeTag<std::wstring>) { + return std::wstring_view(L"{}"); +} + +constexpr std::string_view PlaceHolder(TypeTag<std::string>) { + return std::string_view("{}"); +} + +template <typename TString> +void FormatInternal(TString& string) { + const auto find_result = string.find(PlaceHolder(TypeTag<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(TypeTag<TString>{})); + if (find_result == TString::npos) + throw std::invalid_argument("There is less placeholders than args."); + + string.replace(find_result, 2, FormatToString(arg, TypeTag<TString>{})); + FormatInternal<TString>(string, args...); +} +} // namespace details + +template <typename... T> +std::wstring Format(const std::wstring_view& format, const T&... args) { + std::wstring result(format); + details::FormatInternal<std::wstring>(result, args...); + return result; +} + +template <typename... T> +std::string Format(const std::string_view& format, const T&... args) { + std::string result(format); + details::FormatInternal<std::string>(result, args...); + return result; +} + +#define CRU_FORMAT_NUMBER(type) \ + inline std::string FormatToString(const type number, \ + details::TypeTag<std::string>) { \ + return std::to_string(number); \ + } \ + inline std::wstring FormatToString(const type number, \ + details::TypeTag<std::wstring>) { \ + return std::to_wstring(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 std::wstring_view FormatToString(const std::wstring& string, + details::TypeTag<std::wstring>) { + return string; +} + +inline std::string_view FormatToString(const std::string& string, + details::TypeTag<std::string>) { + return string; +} + +inline std::wstring_view FormatToString(const std::wstring_view& string, + details::TypeTag<String>) { + return string; +} + +inline std::string_view FormatToString(const std::string_view& string, + details::TypeTag<std::string>) { + return string; +} + +inline std::wstring_view FormatToString(const wchar_t* string, + details::TypeTag<String>) { + return std::wstring_view(string); +} + +inline std::string_view FormatToString(const char* string, + details::TypeTag<std::string>) { + return std::string(string); +} +} // namespace cru::util diff --git a/include/cru/common/pre_config.hpp b/include/cru/common/pre_config.hpp new file mode 100644 index 00000000..aa4d680b --- /dev/null +++ b/include/cru/common/pre_config.hpp @@ -0,0 +1,5 @@ +#pragma once + +#ifdef _DEBUG +#define CRU_DEBUG +#endif diff --git a/include/cru/common/ui_base.hpp b/include/cru/common/ui_base.hpp new file mode 100644 index 00000000..42ed0eb4 --- /dev/null +++ b/include/cru/common/ui_base.hpp @@ -0,0 +1,233 @@ +#pragma once +#include "pre_config.hpp" + +#include <utility> +#include <optional> + +namespace cru::ui { +struct Point final { + constexpr Point() = default; + constexpr Point(const float x, const float y) : x(x), y(y) {} + + float x = 0; + float y = 0; +}; + +constexpr bool operator==(const Point& left, const Point& right) { + return left.x == right.x && left.y == right.y; +} + +constexpr bool operator!=(const Point& left, const Point& right) { + return !(left == right); +} + +struct Size final { + constexpr Size() = default; + constexpr Size(const float width, const float height) + : width(width), height(height) {} + + float width = 0; + float height = 0; +}; + +constexpr Size operator+(const Size& left, const Size& right) { + return Size(left.width + right.width, left.height + right.height); +} + +constexpr Size operator-(const Size& left, const Size& right) { + return Size(left.width - right.width, left.height - right.height); +} + +constexpr bool operator==(const Size& left, const Size& right) { + return left.width == right.width && left.height == right.height; +} + +constexpr bool operator!=(const Size& left, const Size& right) { + return !(left == right); +} + +struct Thickness final { + constexpr Thickness() : Thickness(0) {} + + constexpr explicit Thickness(const float width) + : left(width), top(width), right(width), bottom(width) {} + + constexpr explicit Thickness(const float horizontal, const float vertical) + : left(horizontal), top(vertical), right(horizontal), bottom(vertical) {} + + constexpr Thickness(const float left, const float top, const float right, + const float bottom) + : left(left), top(top), right(right), bottom(bottom) {} + + constexpr float GetHorizontalTotal() const { return left + right; } + + constexpr float GetVerticalTotal() const { return top + bottom; } + + void SetLeftRight(const float value) { left = right = value; } + + void SetTopBottom(const float value) { top = bottom = value; } + + void SetAll(const float value) { left = top = right = bottom = value; } + + constexpr float Validate() const { + return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0; + } + + float left; + float top; + float right; + float bottom; +}; + +constexpr bool operator==(const Thickness& left, const Thickness& right) { + return left.left == right.left && left.top == right.top && + left.right == right.right && left.bottom == right.bottom; +} + +constexpr bool operator!=(const Thickness& left, const Thickness& right) { + return !(left == right); +} + +struct Rect final { + constexpr Rect() = default; + constexpr Rect(const float left, const float top, const float width, + const float height) + : left(left), top(top), width(width), height(height) {} + constexpr Rect(const Point& lefttop, const Size& size) + : left(lefttop.x), + top(lefttop.y), + width(size.width), + height(size.height) {} + + constexpr static Rect FromVertices(const float left, const float top, + const float right, const float bottom) { + return Rect(left, top, right - left, bottom - top); + } + + constexpr static Rect FromCenter(const Point& center, const float width, + const float height) { + return Rect(center.x - width / 2.0f, center.y - height / 2.0f, width, + height); + } + + constexpr float GetRight() const { return left + width; } + + constexpr float GetBottom() const { return top + height; } + + constexpr Point GetLeftTop() const { return Point(left, top); } + + constexpr Point GetRightBottom() const { + return Point(left + width, top + height); + } + + constexpr Point GetLeftBottom() const { return Point(left, top + height); } + + constexpr Point GetRightTop() const { return Point(left + width, top); } + + constexpr Point GetCenter() const { + return Point(left + width / 2.0f, top + height / 2.0f); + } + + constexpr Size GetSize() const { return Size(width, height); } + + constexpr Rect Shrink(const Thickness& thickness) const { + return Rect(left + thickness.left, top + thickness.top, + width - thickness.GetHorizontalTotal(), + height - thickness.GetVerticalTotal()); + } + + constexpr bool IsPointInside(const Point& point) const { + return point.x >= left && point.x < GetRight() && point.y >= top && + point.y < GetBottom(); + } + + float left = 0.0f; + float top = 0.0f; + float width = 0.0f; + float height = 0.0f; +}; + +constexpr bool operator==(const Rect& left, const Rect& right) { + return left.left == right.left && left.top == right.top && + left.width == right.width && left.height == right.height; +} + +constexpr bool operator!=(const Rect& left, const Rect& right) { + return !(left == right); +} + +struct RoundedRect final { + constexpr RoundedRect() = default; + constexpr RoundedRect(const Rect& rect, const float radius_x, + const float radius_y) + : rect(rect), radius_x(radius_x), radius_y(radius_y) {} + + Rect rect{}; + float radius_x = 0.0f; + float radius_y = 0.0f; +}; + +constexpr bool operator==(const RoundedRect& left, const RoundedRect& right) { + return left.rect == right.rect && left.radius_x == right.radius_x && + left.radius_y == right.radius_y; +} + +constexpr bool operator!=(const RoundedRect& left, const RoundedRect& right) { + return !(left == right); +} + +struct Ellipse final { + constexpr Ellipse() = default; + constexpr Ellipse(const Point& center, const float radius_x, + const float radius_y) + : center(center), radius_x(radius_x), radius_y(radius_y) {} + + constexpr static Ellipse FromRect(const Rect& rect) { + return Ellipse(rect.GetCenter(), rect.width / 2.0f, rect.height / 2.0f); + } + + constexpr Rect GetBoundRect() const { + return Rect::FromCenter(center, radius_x * 2.0f, radius_y * 2.0f); + } + + Point center{}; + float radius_x = 0.0f; + float radius_y = 0.0f; +}; + +constexpr bool operator==(const Ellipse& left, const Ellipse& right) { + return left.center == right.center && left.radius_x == right.radius_x && + left.radius_y == right.radius_y; +} + +constexpr bool operator!=(const Ellipse& left, const Ellipse& right) { + return !(left == right); +} + +struct TextRange final { + constexpr static std::optional<TextRange> FromTwoSides(unsigned first, + unsigned second) { + if (first > second) + return std::make_optional<TextRange>(second, first - second); + if (first < second) + return std::make_optional<TextRange>(first, second - first); + return std::nullopt; + } + + constexpr static std::pair<unsigned, unsigned> ToTwoSides( + std::optional<TextRange> text_range, unsigned default_position = 0) { + if (text_range.has_value()) + return std::make_pair( + text_range.value().position, + text_range.value().position + text_range.value().count); + return std::make_pair(default_position, default_position); + } + + constexpr TextRange() = default; + constexpr TextRange(const unsigned position, const unsigned count) + : position(position), count(count) {} + + unsigned position = 0; + unsigned count = 0; +}; +} // namespace cru::ui diff --git a/include/cru/platform/debug.hpp b/include/cru/platform/debug.hpp new file mode 100644 index 00000000..24759ee1 --- /dev/null +++ b/include/cru/platform/debug.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "cru/common/pre_config.hpp" + +#include <string_view> + +namespace cru::platform::debug { +void DebugMessage(const std::string_view& message); +} diff --git a/include/cru/platform/native_window.hpp b/include/cru/platform/native_window.hpp new file mode 100644 index 00000000..1ed9a25e --- /dev/null +++ b/include/cru/platform/native_window.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "cru/common/base.hpp" +#include "cru/common/ui_base.hpp" + +namespace cru::platform { +struct Painter; + +struct NativeWindow : public virtual Interface { + virtual bool IsValid() = 0; + + virtual void Close() = 0; + + virtual NativeWindow* GetParent() = 0; + + virtual bool IsVisible() const = 0; + virtual void SetVisible(bool is_visible) = 0; + + virtual ui::Size GetClientSize() = 0; + virtual void SetClientSize(const ui::Size& size) = 0; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual ui::Rect GetWindowRect() = 0; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual void SetWindowRect(const ui::Rect& rect) = 0; + + virtual Painter* GetPainter() = 0; +}; +} // namespace cru::platform diff --git a/include/cru/platform/ui_applicaition.hpp b/include/cru/platform/ui_applicaition.hpp new file mode 100644 index 00000000..1345d38c --- /dev/null +++ b/include/cru/platform/ui_applicaition.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "cru/common/base.hpp" + +#include <chrono> +#include <functional> + +namespace cru::platform { +struct NativeWindow; +struct GraphFactory; + +struct UiApplication : public virtual Interface { + static UiApplication* GetInstance(); + + virtual int Run() = 0; + virtual void Quit(int quite_code) = 0; + + virtual void InvokeLater(const std::function<void()>& action) = 0; + virtual unsigned long SetTimeout(std::chrono::milliseconds milliseconds, + const std::function<void()>& action) = 0; + virtual unsigned long SetInterval(std::chrono::milliseconds milliseconds, + const std::function<void()>& action) = 0; + virtual void CancelTimer(unsigned long id) = 0; + + virtual NativeWindow* CreateWindow() = 0; + + virtual GraphFactory* GetGraphFactory() = 0; +}; +} // namespace cru::platform diff --git a/include/cru/platform/win/exception.hpp b/include/cru/platform/win/exception.hpp new file mode 100644 index 00000000..01b139b4 --- /dev/null +++ b/include/cru/platform/win/exception.hpp @@ -0,0 +1,49 @@ +#pragma once +#include "win_pre_config.hpp" + +#include <stdexcept> +#include <string_view> + +namespace cru::platform::win { +class HResultError : public std::runtime_error { + public: + explicit HResultError(HRESULT h_result); + explicit HResultError(HRESULT h_result, + const std::string_view& additional_message); + HResultError(const HResultError& other) = default; + HResultError(HResultError&& other) = default; + HResultError& operator=(const HResultError& other) = default; + HResultError& operator=(HResultError&& other) = default; + ~HResultError() override = default; + + HRESULT GetHResult() const { return h_result_; } + + private: + HRESULT h_result_; +}; + +inline void ThrowIfFailed(const HRESULT h_result) { + if (FAILED(h_result)) throw HResultError(h_result); +} + +inline void ThrowIfFailed(const HRESULT h_result, + const std::string_view& message) { + if (FAILED(h_result)) throw HResultError(h_result, message); +} + +class Win32Error : public std::runtime_error { + public: + explicit Win32Error(DWORD error_code); + Win32Error(DWORD error_code, const std::string_view& additional_message); + Win32Error(const Win32Error& other) = default; + Win32Error(Win32Error&& other) = default; + Win32Error& operator=(const Win32Error& other) = default; + Win32Error& operator=(Win32Error&& other) = default; + ~Win32Error() override = default; + + HRESULT GetErrorCode() const { return error_code_; } + + private: + DWORD error_code_; +}; +} // namespace cru::platform::win diff --git a/include/cru/platform/win/god_window.hpp b/include/cru/platform/win/god_window.hpp new file mode 100644 index 00000000..534dfedb --- /dev/null +++ b/include/cru/platform/win/god_window.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "win_pre_config.hpp" + +#include <memory> +#include <optional> + +#include "cru/common/base.hpp" + +namespace cru::platform::win { +class WinApplication; +class WindowClass; + +class GodWindow : public Object { + public: + explicit GodWindow(WinApplication* application); + GodWindow(const GodWindow& other) = delete; + GodWindow(GodWindow&& other) = delete; + GodWindow& operator=(const GodWindow& other) = delete; + GodWindow& operator=(GodWindow&& other) = delete; + ~GodWindow() override; + + HWND GetHandle() const { return hwnd_; } + + std::optional<LRESULT> HandleGodWindowMessage(HWND hwnd, int msg, + WPARAM w_param, LPARAM l_param); + + private: + WinApplication* application_; + + std::shared_ptr<WindowClass> god_window_class_; + HWND hwnd_; +}; +} // namespace cru::platform::win
\ No newline at end of file diff --git a/include/cru/platform/win/win_application.hpp b/include/cru/platform/win/win_application.hpp new file mode 100644 index 00000000..363ae170 --- /dev/null +++ b/include/cru/platform/win/win_application.hpp @@ -0,0 +1,53 @@ +#pragma once +#include "win_pre_config.hpp" + +#include "../ui_applicaition.hpp" +#include "cru/common/base.hpp" + +#include <memory> + +namespace cru::platform::win { +class GodWindow; +class TimerManager; + +class WinApplication : public Object, public virtual UiApplication { + public: + static WinApplication* GetInstance(); + + private: + static WinApplication* instance_; + + private: + explicit WinApplication(HINSTANCE h_instance); + + public: + WinApplication(const WinApplication&) = delete; + WinApplication(WinApplication&&) = delete; + WinApplication& operator=(const WinApplication&) = delete; + WinApplication& operator=(WinApplication&&) = delete; + ~WinApplication() override; + + public: + int Run() override; + void Quit(int quit_code) override; + + void InvokeLater(const std::function<void()>& action) override; + unsigned long SetTimeout(std::chrono::milliseconds milliseconds, + const std::function<void()>& action) override; + unsigned long SetInterval(std::chrono::milliseconds milliseconds, + const std::function<void()>& action) override; + void CancelTimer(unsigned long id) override; + + HINSTANCE GetInstanceHandle() const { return h_instance_; } + + GodWindow* GetGodWindow() const { return god_window_.get(); } + + TimerManager* GetTimerManager() const; + + private: + HINSTANCE h_instance_; + + std::shared_ptr<GodWindow> god_window_; + std::shared_ptr<TimerManager> timer_manager_; +}; +} // namespace cru::platform::win diff --git a/include/cru/platform/win/win_pre_config.hpp b/include/cru/platform/win/win_pre_config.hpp new file mode 100644 index 00000000..2e8bb80e --- /dev/null +++ b/include/cru/platform/win/win_pre_config.hpp @@ -0,0 +1,6 @@ +#include "cru/common/pre_config.hpp" + +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#undef CreateWindow diff --git a/include/cru/platform/win/window_class.hpp b/include/cru/platform/win/window_class.hpp new file mode 100644 index 00000000..be79af13 --- /dev/null +++ b/include/cru/platform/win/window_class.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "win_pre_config.hpp" + +#include "cru/common/base.hpp" + +#include <string> + +namespace cru::platform::win { +class WindowClass : public Object { + public: + WindowClass(const std::wstring& name, WNDPROC window_proc, HINSTANCE h_instance); + WindowClass(const WindowClass& other) = delete; + WindowClass(WindowClass&& other) = delete; + WindowClass& operator=(const WindowClass& other) = delete; + WindowClass& operator=(WindowClass&& other) = delete; + ~WindowClass() override = default; + + const wchar_t* GetName() const { return name_.c_str(); } + + ATOM GetAtom() const { return atom_; } + + private: + std::wstring name_; + ATOM atom_; +}; +} // namespace cru::ui |