From e69911a8b161b81ce3f7b209175766da2b7b3d4b Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 12 Dec 2019 19:53:17 +0800 Subject: ... --- .gitignore | 1 + .vscode/c_cpp_properties.json | 9 + .vscode/settings.json | 62 ++++++ include/cru/common/base.hpp | 12 +- include/cru/common/logger.hpp | 51 ++--- include/cru/common/pre_config.hpp | 5 + include/cru/platform/check.hpp | 41 ++++ include/cru/platform/exception.hpp | 14 +- include/cru/platform/graph/base.hpp | 4 + include/cru/platform/graph/brush.hpp | 45 +--- include/cru/platform/graph/factory.hpp | 27 +++ include/cru/platform/graph/font.hpp | 16 +- include/cru/platform/graph/geometry.hpp | 37 +--- include/cru/platform/graph/graph_factory.hpp | 62 ------ include/cru/platform/graph/painter.hpp | 37 +--- include/cru/platform/graph/resource.hpp | 10 + include/cru/platform/graph/text_layout.hpp | 28 +-- include/cru/platform/graph/util/painter.hpp | 17 ++ include/cru/platform/graph/util/painter_util.hpp | 18 -- include/cru/platform/graph_base.hpp | 271 +++++++++++++++++++++++ include/cru/platform/graphic_base.hpp | 271 ----------------------- include/cru/platform/heap_debug.hpp | 3 +- include/cru/platform/matrix.hpp | 10 +- include/cru/platform/native/basic_types.hpp | 2 +- include/cru/platform/native/cursor.hpp | 29 +-- include/cru/platform/native/native_event.hpp | 5 + include/cru/platform/native/native_window.hpp | 34 ++- include/cru/platform/native/ui_application.hpp | 35 ++- include/cru/platform/native_resource.hpp | 23 -- include/cru/platform/resource.hpp | 10 + include/cru/platform/string_util.hpp | 9 - include/cru/ui/render/border_render_object.hpp | 8 +- include/cru/ui/window.hpp | 6 +- include/cru/win/graph/direct/brush.hpp | 33 ++- include/cru/win/graph/direct/com_resource.hpp | 10 +- include/cru/win/graph/direct/convert_util.hpp | 9 +- include/cru/win/graph/direct/direct_factory.hpp | 16 -- include/cru/win/graph/direct/factory.hpp | 48 ++++ include/cru/win/graph/direct/font.hpp | 23 +- include/cru/win/graph/direct/geometry.hpp | 41 ++-- include/cru/win/graph/direct/graph_factory.hpp | 71 ------ include/cru/win/graph/direct/painter.hpp | 28 ++- include/cru/win/graph/direct/platform_id.hpp | 18 -- include/cru/win/graph/direct/resource.hpp | 49 ++++ include/cru/win/graph/direct/text_layout.hpp | 39 ++-- include/cru/win/native/native_window.hpp | 2 +- include/cru/win/native/platform_id.hpp | 19 -- include/cru/win/native/ui_application.hpp | 4 +- include/cru/win/string.hpp | 10 + src/common/CMakeLists.txt | 2 +- src/common/logger.cpp | 37 ++-- src/platform/CMakeLists.txt | 6 +- src/platform/graph/CMakeLists.txt | 6 +- src/platform/native/CMakeLists.txt | 8 +- src/platform/native/cursor.cpp | 10 - src/win/CMakeLists.txt | 3 +- src/win/debug_logger.hpp | 6 +- src/win/graph/direct/CMakeLists.txt | 8 +- src/win/graph/direct/brush.cpp | 7 +- src/win/graph/direct/factory.cpp | 79 +++++++ src/win/graph/direct/font.cpp | 20 +- src/win/graph/direct/geometry.cpp | 22 +- src/win/graph/direct/graph_factory.cpp | 111 ---------- src/win/graph/direct/painter.cpp | 80 +++---- src/win/graph/direct/resource.cpp | 14 ++ src/win/graph/direct/text_layout.cpp | 47 ++-- src/win/native/CMakeLists.txt | 1 - src/win/native/ui_application.cpp | 8 +- src/win/string.cpp | 46 ++++ src/win/string_util.cpp | 20 -- 70 files changed, 1036 insertions(+), 1137 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 include/cru/platform/check.hpp create mode 100644 include/cru/platform/graph/base.hpp create mode 100644 include/cru/platform/graph/factory.hpp delete mode 100644 include/cru/platform/graph/graph_factory.hpp create mode 100644 include/cru/platform/graph/resource.hpp create mode 100644 include/cru/platform/graph/util/painter.hpp delete mode 100644 include/cru/platform/graph/util/painter_util.hpp create mode 100644 include/cru/platform/graph_base.hpp delete mode 100644 include/cru/platform/graphic_base.hpp delete mode 100644 include/cru/platform/native_resource.hpp create mode 100644 include/cru/platform/resource.hpp delete mode 100644 include/cru/platform/string_util.hpp delete mode 100644 include/cru/win/graph/direct/direct_factory.hpp create mode 100644 include/cru/win/graph/direct/factory.hpp delete mode 100644 include/cru/win/graph/direct/graph_factory.hpp delete mode 100644 include/cru/win/graph/direct/platform_id.hpp create mode 100644 include/cru/win/graph/direct/resource.hpp delete mode 100644 include/cru/win/native/platform_id.hpp create mode 100644 include/cru/win/string.hpp delete mode 100644 src/platform/native/cursor.cpp create mode 100644 src/win/graph/direct/factory.cpp delete mode 100644 src/win/graph/direct/graph_factory.cpp create mode 100644 src/win/graph/direct/resource.cpp create mode 100644 src/win/string.cpp delete mode 100644 src/win/string_util.cpp diff --git a/.gitignore b/.gitignore index 8500f266..058ed33c 100644 --- a/.gitignore +++ b/.gitignore @@ -179,6 +179,7 @@ dmypy.json ### VisualStudioCode ### .vscode/* +!.vscode/c_cpp_properties.json !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..f5500679 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,9 @@ +{ + "configurations": [ + { + "name": "Win32", + "configurationProvider": "ms-vscode.cmake-tools" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..edf04435 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,62 @@ +{ + "files.associations": { + "algorithm": "cpp", + "array": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cmath": "cpp", + "concepts": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "forward_list": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "map": "cpp", + "memory": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocinfo": "cpp", + "xlocnum": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "atomic": "cpp", + "clocale": "cpp", + "condition_variable": "cpp", + "mutex": "cpp", + "shared_mutex": "cpp", + "thread": "cpp" + } +} \ No newline at end of file diff --git a/include/cru/common/base.hpp b/include/cru/common/base.hpp index 55f43e5c..2c935046 100644 --- a/include/cru/common/base.hpp +++ b/include/cru/common/base.hpp @@ -23,19 +23,15 @@ namespace cru { class Object { public: Object() = default; - Object(const Object&) = default; - Object& operator=(const Object&) = default; - Object(Object&&) = default; - Object& operator=(Object&&) = default; + CRU_DEFAULT_COPY(Object) + CRU_DEFAULT_MOVE(Object) virtual ~Object() = default; }; struct Interface { Interface() = default; - Interface(const Interface& other) = delete; - Interface(Interface&& other) = delete; - Interface& operator=(const Interface& other) = delete; - Interface& operator=(Interface&& other) = delete; + CRU_DELETE_COPY(Interface) + CRU_DELETE_MOVE(Interface) virtual ~Interface() = default; }; diff --git a/include/cru/common/logger.hpp b/include/cru/common/logger.hpp index bbe06331..08765499 100644 --- a/include/cru/common/logger.hpp +++ b/include/cru/common/logger.hpp @@ -5,32 +5,33 @@ #include #include +#include #include namespace cru::log { enum class LogLevel { Debug, Info, Warn, Error }; -struct ILoggerSource : Interface { - // Write the s. LogLevel is just a helper. It has no effect on the content to - // write. - virtual void Write(LogLevel level, const std::wstring_view& s) = 0; +struct ILogSource : virtual Interface { + // Write the string s. LogLevel is just a helper. It has no effect on the + // content to write. + virtual void Write(LogLevel level, const std::string_view& s) = 0; }; -class StdioLoggerSource : public ILoggerSource { +class StdioLogSource : public virtual ILogSource { public: - StdioLoggerSource() = default; + StdioLogSource() = default; - CRU_DELETE_COPY(StdioLoggerSource) - CRU_DELETE_MOVE(StdioLoggerSource) + CRU_DELETE_COPY(StdioLogSource) + CRU_DELETE_MOVE(StdioLogSource) - ~StdioLoggerSource() = default; + ~StdioLogSource() override = default; - void Write(LogLevel level, const std::wstring_view& s) override { + void Write(LogLevel level, const std::string_view& s) override { if (level == LogLevel::Error) { - std::wcerr << s; + std::cerr << s; } else { - std::wcout << s; + std::cout << s; } } }; @@ -45,43 +46,43 @@ class Logger : public Object { CRU_DELETE_COPY(Logger) CRU_DELETE_MOVE(Logger) - ~Logger() override; + ~Logger() override = default; public: - void AddSource(ILoggerSource* source); - void RemoveSource(ILoggerSource* source); + void AddSource(std::unique_ptr source); + void RemoveSource(ILogSource* source); public: - void Log(LogLevel level, const std::wstring_view& s); + void Log(LogLevel level, const std::string_view& s); template - void Debug(const std::wstring_view& format, TArgs&&... args) { + void Debug(const std::string_view& format, TArgs&&... args) { #ifdef CRU_DEBUG Log(LogLevel::Debug, util::Format(format, std::forward(args)...)); #endif } template - void Info(const std::wstring_view& format, TArgs&&... args) { + void Info(const std::string_view& format, TArgs&&... args) { Log(LogLevel::Info, util::Format(format, std::forward(args)...)); } template - void Warn(const std::wstring_view& format, TArgs&&... args) { + void Warn(const std::string_view& format, TArgs&&... args) { Log(LogLevel::Warn, util::Format(format, std::forward(args)...)); } template - void Error(const std::wstring_view& format, TArgs&&... args) { + void Error(const std::string_view& format, TArgs&&... args) { Log(LogLevel::Error, util::Format(format, std::forward(args)...)); } public: - std::list sources_; + std::list> sources_; }; template -void Debug(const std::wstring_view& format, TArgs&&... args) { +void Debug(const std::string_view& format, TArgs&&... args) { #ifdef CRU_DEBUG Logger::GetInstance()->Log( LogLevel::Debug, util::Format(format, std::forward(args)...)); @@ -89,19 +90,19 @@ void Debug(const std::wstring_view& format, TArgs&&... args) { } template -void Info(const std::wstring_view& format, TArgs&&... args) { +void Info(const std::string_view& format, TArgs&&... args) { Logger::GetInstance()->Log( LogLevel::Info, util::Format(format, std::forward(args)...)); } template -void Warn(const std::wstring_view& format, TArgs&&... args) { +void Warn(const std::string_view& format, TArgs&&... args) { Logger::GetInstance()->Log( LogLevel::Warn, util::Format(format, std::forward(args)...)); } template -void Error(const std::wstring_view& format, TArgs&&... args) { +void Error(const std::string_view& format, TArgs&&... args) { Logger::GetInstance()->Log( LogLevel::Error, util::Format(format, std::forward(args)...)); } diff --git a/include/cru/common/pre_config.hpp b/include/cru/common/pre_config.hpp index 96b1bab5..5fcef218 100644 --- a/include/cru/common/pre_config.hpp +++ b/include/cru/common/pre_config.hpp @@ -1,5 +1,10 @@ #pragma once +#ifdef _MSC_VER +// disable the unnecessary warning about multi-inheritance +#pragma warning(disable : 4250) +#endif + #ifdef _DEBUG #define CRU_DEBUG #endif diff --git a/include/cru/platform/check.hpp b/include/cru/platform/check.hpp new file mode 100644 index 00000000..8e60e848 --- /dev/null +++ b/include/cru/platform/check.hpp @@ -0,0 +1,41 @@ +#pragma once +#include "cru/common/format.hpp" +#include "exception.hpp" +#include "resource.hpp" + +#include +#include +#include + +namespace cru::platform { +template +TTarget* CheckPlatform(INativeResource* resource, + const std::string_view& target_platform) { + assert(resource); + const auto result = dynamic_cast(resource); + if (result == nullptr) { + throw UnsupportPlatformException(util::Format( + "Try to convert resource to target platform failed. Platform id of " + "resource to convert: {} . Target platform id: {} .", + resource->GetPlatformId(), target_platform)); + } + return result; +} + +template +std::shared_ptr CheckPlatform( + const std::shared_ptr& resource, + const std::string_view& target_platform) { + static_assert(std::is_base_of_v, + "TSource must be a subclass of INativeResource."); + assert(resource); + const auto result = std::dynamic_pointer_cast(resource); + if (result == nullptr) { + throw UnsupportPlatformException(util::Format( + "Try to convert resource to target platform failed. Platform id of " + "resource to convert: {} . Target platform id: {} .", + resource->GetPlatformId(), target_platform)); + } + return result; +} +} // namespace cru::platform diff --git a/include/cru/platform/exception.hpp b/include/cru/platform/exception.hpp index ad6827c0..1774b12c 100644 --- a/include/cru/platform/exception.hpp +++ b/include/cru/platform/exception.hpp @@ -9,10 +9,18 @@ class PlatformException : public std::runtime_error { using runtime_error::runtime_error; // inherit constructors }; -// This exception is throwed when a resource has been disposed and not usable +// This exception is thrown when a resource is used on another platform. +// Of course, you can't mix resources of two different platform. +// For example, Win32 Brush (may add in the future) with Direct Painter. +class UnsupportPlatformException : public std::runtime_error { + public: + using runtime_error::runtime_error; // inherit constructors +}; + +// This exception is thrown when a resource has been disposed and not usable // again. -// For example, calling Build twice on a GeometryBuilder::Build will lead to this -// exception. +// For example, calling Build twice on a GeometryBuilder::Build will lead to +// this exception. class ReuseException : public std::runtime_error { public: using runtime_error::runtime_error; // inherit constructors diff --git a/include/cru/platform/graph/base.hpp b/include/cru/platform/graph/base.hpp new file mode 100644 index 00000000..8c2a2d2f --- /dev/null +++ b/include/cru/platform/graph/base.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "../graph_base.hpp" +#include "../matrix.hpp" +#include "../resource.hpp" diff --git a/include/cru/platform/graph/brush.hpp b/include/cru/platform/graph/brush.hpp index d292ae82..af7a1dec 100644 --- a/include/cru/platform/graph/brush.hpp +++ b/include/cru/platform/graph/brush.hpp @@ -1,46 +1,11 @@ #pragma once -#include "../graphic_base.hpp" -#include "../native_resource.hpp" +#include "resource.hpp" namespace cru::platform::graph { -class Brush : public NativeResource { - protected: - Brush() = default; +struct IBrush : virtual IGraphResource {}; - public: - Brush(const Brush& other) = delete; - Brush& operator=(const Brush& other) = delete; - - Brush(Brush&& other) = delete; - Brush& operator=(Brush&& other) = delete; - - ~Brush() override = default; -}; - -class SolidColorBrush : public Brush { - protected: - SolidColorBrush() = default; - - public: - SolidColorBrush(const SolidColorBrush& other) = delete; - SolidColorBrush& operator=(const SolidColorBrush& other) = delete; - - SolidColorBrush(SolidColorBrush&& other) = delete; - SolidColorBrush& operator=(SolidColorBrush&& other) = delete; - - ~SolidColorBrush() = default; - - public: - Color GetColor() { return color_; } - void SetColor(const Color& color) { - color_ = color; - OnSetColor(color); - } - - protected: - virtual void OnSetColor(const Color& color) = 0; - - protected: - Color color_ = colors::black; +struct ISolidColorBrush : virtual IBrush { + virtual Color GetColor() = 0; + virtual void SetColor(const Color& color) = 0; }; } // namespace cru::platform::graph diff --git a/include/cru/platform/graph/factory.hpp b/include/cru/platform/graph/factory.hpp new file mode 100644 index 00000000..2c52cbb8 --- /dev/null +++ b/include/cru/platform/graph/factory.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "base.hpp" + +#include "brush.hpp" +#include "font.hpp" +#include "geometry.hpp" +#include "text_layout.hpp" + +#include +#include +#include +#include + +namespace cru::platform::graph { +// Entry point of the graph module. +struct IGraphFactory : virtual INativeResource { + virtual std::unique_ptr CreateSolidColorBrush() = 0; + + virtual std::unique_ptr CreateGeometryBuilder() = 0; + + virtual std::unique_ptr CreateFont(const std::string_view& font_family, + float font_size) = 0; + + virtual std::unique_ptr CreateTextLayout( + std::shared_ptr font, std::string text) = 0; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/font.hpp b/include/cru/platform/graph/font.hpp index bd470256..98ce80e7 100644 --- a/include/cru/platform/graph/font.hpp +++ b/include/cru/platform/graph/font.hpp @@ -1,18 +1,6 @@ #pragma once -#include "../native_resource.hpp" +#include "resource.hpp" namespace cru::platform::graph { -class Font : public NativeResource { - protected: - Font() = default; - - public: - Font(const Font& other) = delete; - Font& operator=(const Font& other) = delete; - - Font(Font&& other) = delete; - Font& operator=(Font&& other) = delete; - - ~Font() override = default; -}; +struct IFont : virtual IGraphResource {}; } // namespace cru::platform::graph diff --git a/include/cru/platform/graph/geometry.hpp b/include/cru/platform/graph/geometry.hpp index d31b3b27..689b2ab9 100644 --- a/include/cru/platform/graph/geometry.hpp +++ b/include/cru/platform/graph/geometry.hpp @@ -1,45 +1,22 @@ #pragma once -#include "../graphic_base.hpp" -#include "../native_resource.hpp" +#include "resource.hpp" -namespace cru::platform::graph { -class Geometry : public NativeResource { - protected: - Geometry() = default; - - public: - Geometry(const Geometry& other) = delete; - Geometry& operator=(const Geometry& other) = delete; - - Geometry(Geometry&& other) = delete; - Geometry& operator=(Geometry&& other) = delete; - - ~Geometry() override = default; +#include - public: +namespace cru::platform::graph { +struct IGeometry : virtual IGraphResource { virtual bool FillContains(const Point& point) = 0; }; -class GeometryBuilder : public NativeResource { - protected: - GeometryBuilder() = default; - - public: - GeometryBuilder(const GeometryBuilder& other) = delete; - GeometryBuilder& operator=(const GeometryBuilder& other) = delete; - - GeometryBuilder(GeometryBuilder&& other) = delete; - GeometryBuilder& operator=(GeometryBuilder&& other) = delete; - - ~GeometryBuilder() override = default; +// After called Build, calling every method will throw a - public: +class IGeometryBuilder : virtual IGraphResource { virtual void BeginFigure(const Point& point) = 0; virtual void LineTo(const Point& point) = 0; virtual void QuadraticBezierTo(const Point& control_point, const Point& end_point) = 0; virtual void CloseFigure(bool close) = 0; - virtual Geometry* Build() = 0; + virtual std::unique_ptr Build() = 0; }; } // namespace cru::platform::graph diff --git a/include/cru/platform/graph/graph_factory.hpp b/include/cru/platform/graph/graph_factory.hpp deleted file mode 100644 index 0b1034cc..00000000 --- a/include/cru/platform/graph/graph_factory.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include "../graphic_base.hpp" -#include "../native_resource.hpp" - -#include "brush.hpp" -#include "font.hpp" -#include "geometry.hpp" -#include "text_layout.hpp" - -#include -#include -#include - -namespace cru::platform::graph { -// Entry point of the graph module. -// If you create a IUiApplication instance, then you should not create -// IGraphFactory manually. IUiApplication will call -// IGraphFactory::CreateInstance and set auto-delete to true. -// The manual creation method of IGraphFactory provides a you a way to use graph -// related tools without interact with actual ui like window system. -class GraphFactory : public NativeResource { - public: - // Create a platform-specific instance and save it as the global instance. - // Do not create the instance twice. Implements should assert for that. - // After creating, get the instance by GetInstance. - static GraphFactory* CreateInstance(); - - // Get the global instance. If it is not created, then return nullptr. - static GraphFactory* GetInstance(); - - protected: - GraphFactory() = default; - - public: - GraphFactory(const GraphFactory& other) = delete; - GraphFactory& operator=(const GraphFactory& other) = delete; - - GraphFactory(GraphFactory&& other) = delete; - GraphFactory& operator=(GraphFactory&& other) = delete; - - ~GraphFactory() override = default; - - public: - virtual SolidColorBrush* CreateSolidColorBrush() = 0; - SolidColorBrush* CreateSolidColorBrush(const Color& color) { - const auto brush = CreateSolidColorBrush(); - brush->SetColor(color); - return brush; - } - - virtual GeometryBuilder* CreateGeometryBuilder() = 0; - - virtual Font* CreateFont(const std::wstring_view& font_family, - float font_size) = 0; - - virtual TextLayout* CreateTextLayout(std::shared_ptr font, - std::wstring text) = 0; - - virtual bool IsAutoDelete() const = 0; - virtual void SetAutoDelete(bool value) = 0; -}; -} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/painter.hpp b/include/cru/platform/graph/painter.hpp index 97d4b4cf..3ae9cf1c 100644 --- a/include/cru/platform/graph/painter.hpp +++ b/include/cru/platform/graph/painter.hpp @@ -1,42 +1,27 @@ #pragma once -#include "../graphic_base.hpp" -#include "../matrix.hpp" -#include "../native_resource.hpp" +#include "base.hpp" namespace cru::platform::graph { -class Brush; -class Geometry; -class TextLayout; +struct IBrush; +struct IGeometry; +struct ITextLayout; -class Painter : public NativeResource { - protected: - Painter() = default; - - public: - Painter(const Painter& other) = delete; - Painter& operator=(const Painter& other) = delete; - - Painter(Painter&& other) = delete; - Painter& operator=(Painter&& other) = delete; - - ~Painter() override = default; - - public: +struct IPainter : virtual INativeResource { virtual Matrix GetTransform() = 0; virtual void SetTransform(const Matrix& matrix) = 0; virtual void Clear(const Color& color) = 0; - virtual void StrokeRectangle(const Rect& rectangle, Brush* brush, + virtual void StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) = 0; - virtual void FillRectangle(const Rect& rectangle, Brush* brush) = 0; + virtual void FillRectangle(const Rect& rectangle, IBrush* brush) = 0; - virtual void StrokeGeometry(Geometry* geometry, Brush* brush, + virtual void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) = 0; - virtual void FillGeometry(Geometry* geometry, Brush* brush) = 0; + virtual void FillGeometry(IGeometry* geometry, IBrush* brush) = 0; - virtual void DrawText(const Point& offset, TextLayout* text_layout, - Brush* brush) = 0; + virtual void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) = 0; virtual void EndDraw() = 0; }; diff --git a/include/cru/platform/graph/resource.hpp b/include/cru/platform/graph/resource.hpp new file mode 100644 index 00000000..255865eb --- /dev/null +++ b/include/cru/platform/graph/resource.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "base.hpp" + +namespace cru::platform::graph { +struct IGraphFactory; + +struct IGraphResource : virtual INativeResource { + virtual IGraphFactory* GetGraphFactory() = 0; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/text_layout.hpp b/include/cru/platform/graph/text_layout.hpp index 56943098..4f6e81e1 100644 --- a/include/cru/platform/graph/text_layout.hpp +++ b/include/cru/platform/graph/text_layout.hpp @@ -1,33 +1,19 @@ #pragma once -#include "../graphic_base.hpp" -#include "../native_resource.hpp" +#include "resource.hpp" #include #include #include namespace cru::platform::graph { -class Font; +struct IFont; -class TextLayout : public NativeResource { - protected: - TextLayout() = default; +struct ITextLayout : virtual IGraphResource { + virtual std::string GetText() = 0; + virtual void SetText(std::string new_text) = 0; - public: - TextLayout(const TextLayout& other) = delete; - TextLayout& operator=(const TextLayout& other) = delete; - - TextLayout(TextLayout&& other) = delete; - TextLayout& operator=(TextLayout&& other) = delete; - - ~TextLayout() override = default; - - public: - virtual std::wstring GetText() = 0; - virtual void SetText(std::wstring new_text) = 0; - - virtual std::shared_ptr GetFont() = 0; - virtual void SetFont(std::shared_ptr font) = 0; + virtual std::shared_ptr GetFont() = 0; + virtual void SetFont(std::shared_ptr font) = 0; virtual void SetMaxWidth(float max_width) = 0; virtual void SetMaxHeight(float max_height) = 0; diff --git a/include/cru/platform/graph/util/painter.hpp b/include/cru/platform/graph/util/painter.hpp new file mode 100644 index 00000000..72d96bc1 --- /dev/null +++ b/include/cru/platform/graph/util/painter.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "../painter.hpp" + +#include +#include + +namespace cru::platform::graph::util { +template +void WithTransform(IPainter* painter, const Matrix& matrix, const Fn& action) { + static_assert(std::is_invocable_v, + "Action must can be be invoked with painter."); + const auto old = painter->GetTransform(); + painter->SetTransform(old * matrix); + action(painter); + painter->SetTransform(old); +} +} // namespace cru::platform::graph::util diff --git a/include/cru/platform/graph/util/painter_util.hpp b/include/cru/platform/graph/util/painter_util.hpp deleted file mode 100644 index 7a655a34..00000000 --- a/include/cru/platform/graph/util/painter_util.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "../painter.hpp" - -#include -#include - -namespace cru::platform::graph::util { -template -inline void WithTransform(Painter* painter, const Matrix& matrix, - const Fn& action) { - static_assert(std::is_invocable_v, - "Action must can be be invoked with painter."); - const auto old = painter->GetTransform(); - painter->SetTransform(old * matrix); - action(painter); - painter->SetTransform(old); -} -} // namespace cru::platform::util diff --git a/include/cru/platform/graph_base.hpp b/include/cru/platform/graph_base.hpp new file mode 100644 index 00000000..c9c4f629 --- /dev/null +++ b/include/cru/platform/graph_base.hpp @@ -0,0 +1,271 @@ +#pragma once +#include "cru/common/pre_config.hpp" + +#include +#include +#include + +namespace cru::platform { +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 Point operator+(const Point& left, const Point& right) { + return Point(left.x + right.x, left.y + right.y); +} + +constexpr Point operator-(const Point& left, const Point& right) { + return Point(left.x - right.x, left.y - right.y); +} + +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 FromTwoSides(unsigned first, + unsigned second) { + if (first > second) + return std::make_optional(second, first - second); + if (first < second) + return std::make_optional(first, second - first); + return std::nullopt; + } + + constexpr static std::pair ToTwoSides( + std::optional 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; +}; + +struct Color { + constexpr Color() : Color(0, 0, 0, 255) {} + constexpr Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, + std::uint8_t alpha = 255) + : red(red), green(green), blue(blue), alpha(alpha) {} + + constexpr static Color FromHex(std::uint32_t hex) { + const std::uint32_t mask = 0b11111111; + return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, 255); + } + + constexpr static Color FromHexAlpha(std::uint32_t hex) { + const std::uint32_t mask = 0b11111111; + return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, + (hex >> 24) & mask); + } + + std::uint8_t red; + std::uint8_t green; + std::uint8_t blue; + std::uint8_t alpha; +}; + +namespace colors { +constexpr Color black{0, 0, 0}; +constexpr Color white{255, 255, 255}; +constexpr Color skyblue = Color::FromHex(0x87ceeb); +} // namespace colors +} // namespace cru::platform diff --git a/include/cru/platform/graphic_base.hpp b/include/cru/platform/graphic_base.hpp deleted file mode 100644 index c9c4f629..00000000 --- a/include/cru/platform/graphic_base.hpp +++ /dev/null @@ -1,271 +0,0 @@ -#pragma once -#include "cru/common/pre_config.hpp" - -#include -#include -#include - -namespace cru::platform { -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 Point operator+(const Point& left, const Point& right) { - return Point(left.x + right.x, left.y + right.y); -} - -constexpr Point operator-(const Point& left, const Point& right) { - return Point(left.x - right.x, left.y - right.y); -} - -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 FromTwoSides(unsigned first, - unsigned second) { - if (first > second) - return std::make_optional(second, first - second); - if (first < second) - return std::make_optional(first, second - first); - return std::nullopt; - } - - constexpr static std::pair ToTwoSides( - std::optional 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; -}; - -struct Color { - constexpr Color() : Color(0, 0, 0, 255) {} - constexpr Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, - std::uint8_t alpha = 255) - : red(red), green(green), blue(blue), alpha(alpha) {} - - constexpr static Color FromHex(std::uint32_t hex) { - const std::uint32_t mask = 0b11111111; - return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, 255); - } - - constexpr static Color FromHexAlpha(std::uint32_t hex) { - const std::uint32_t mask = 0b11111111; - return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, - (hex >> 24) & mask); - } - - std::uint8_t red; - std::uint8_t green; - std::uint8_t blue; - std::uint8_t alpha; -}; - -namespace colors { -constexpr Color black{0, 0, 0}; -constexpr Color white{255, 255, 255}; -constexpr Color skyblue = Color::FromHex(0x87ceeb); -} // namespace colors -} // namespace cru::platform diff --git a/include/cru/platform/heap_debug.hpp b/include/cru/platform/heap_debug.hpp index e305be31..9e3ae368 100644 --- a/include/cru/platform/heap_debug.hpp +++ b/include/cru/platform/heap_debug.hpp @@ -2,5 +2,6 @@ #include "cru/common/pre_config.hpp" namespace cru::platform { +// Setup the heap debug function. Currently I only use this on Windows... void SetupHeapDebug(); -} +} // namespace cru::platform diff --git a/include/cru/platform/matrix.hpp b/include/cru/platform/matrix.hpp index cbb55c78..030e1378 100644 --- a/include/cru/platform/matrix.hpp +++ b/include/cru/platform/matrix.hpp @@ -1,5 +1,5 @@ #pragma once -#include "graphic_base.hpp" +#include "graph_base.hpp" #include @@ -39,7 +39,7 @@ struct Matrix { Point TransformPoint(const Point& point) const { return Point{point.x * m11 + point.y * m21 + m31, - point.x * m12 + point.y * m22 + m32}; + point.x * m12 + point.y * m22 + m32}; } static Matrix Identity() { @@ -50,10 +50,8 @@ struct Matrix { return Matrix{1.0f, 0.0f, 0.0f, 1.0f, x, y}; } - static Matrix Scale(float sx, float sy) { return Scale(sx, sy, 0.0f, 0.0f); } - - static Matrix Scale(float sx, float sy, float cx, float cy) { - return Matrix{sx, 0.0f, 0.0f, sy, cx - sx * cx, cy - sy * cy}; + static Matrix Scale(float sx, float sy) { + return Matrix{sx, 0.0f, 0.0f, sy, 0.0f, 0.0f}; } static Matrix Rotation(float angle) { diff --git a/include/cru/platform/native/basic_types.hpp b/include/cru/platform/native/basic_types.hpp index 5a7155ee..a53fa671 100644 --- a/include/cru/platform/native/basic_types.hpp +++ b/include/cru/platform/native/basic_types.hpp @@ -7,5 +7,5 @@ struct Dpi { float y; }; -enum MouseButton : unsigned { Left = 1, Right = 2, Middle = 4 }; +enum MouseButton : unsigned { Left = 0b1, Right = 0b10, Middle = 0b100 }; } // namespace cru::platform::native diff --git a/include/cru/platform/native/cursor.hpp b/include/cru/platform/native/cursor.hpp index b8604ecb..961dff34 100644 --- a/include/cru/platform/native/cursor.hpp +++ b/include/cru/platform/native/cursor.hpp @@ -5,35 +5,16 @@ #include namespace cru::platform::native { -class Cursor : public NativeResource { - public: - Cursor() = default; +struct ICursor : public virtual INativeResource {}; - CRU_DELETE_COPY(Cursor) - CRU_DELETE_MOVE(Cursor) - - ~Cursor() override = default; -}; - -enum class SystemCursor { +enum class SystemCursorType { Arrow, Hand, }; -class CursorManager : public NativeResource { - public: - CursorManager() = default; - - CRU_DELETE_COPY(CursorManager) - CRU_DELETE_MOVE(CursorManager) +struct ICursorManager : public virtual INativeResource { + virtual std::shared_ptr GetSystemCursor(SystemCursorType type) = 0; - ~CursorManager() override = default; - - public: - virtual std::shared_ptr GetSystemCursor(SystemCursor type) = 0; - - //TODO: Add method to create cursor. + // TODO: Add method to create cursor. }; - -std::shared_ptr GetSystemCursor(SystemCursor type); } // namespace cru::platform::native diff --git a/include/cru/platform/native/native_event.hpp b/include/cru/platform/native/native_event.hpp index 54bab00c..dcd7a336 100644 --- a/include/cru/platform/native/native_event.hpp +++ b/include/cru/platform/native/native_event.hpp @@ -8,4 +8,9 @@ struct NativeMouseButtonEventArgs { MouseButton button; Point point; }; + +enum class FocusChangeType { Gain, Lost }; + +enum class MouseEnterLeaveType { Enter, Leave }; + } // namespace cru::platform::native diff --git a/include/cru/platform/native/native_window.hpp b/include/cru/platform/native/native_window.hpp index 8a067a4c..cd2459e0 100644 --- a/include/cru/platform/native/native_window.hpp +++ b/include/cru/platform/native/native_window.hpp @@ -9,7 +9,7 @@ #include "native_event.hpp" namespace cru::platform::graph { -class Painter; +struct IPainter; } namespace cru::platform::native { @@ -21,28 +21,18 @@ namespace cru::platform::native { // Close or closed by the user, which leads to an invalid instance. You can // check the validity by IsValid. When you call perform native operations on the // invalid instance, there is no effect. -class NativeWindow : public NativeResource { - protected: - NativeWindow() = default; - - public: - NativeWindow(const NativeWindow& other) = delete; - NativeWindow& operator=(const NativeWindow& other) = delete; - - NativeWindow(NativeWindow&& other) = delete; - NativeWindow& operator=(NativeWindow&& other) = delete; - - ~NativeWindow() override = default; - - public: +struct INativeWindow : public virtual INativeResource { // Return if the window is still valid, that is, hasn't been closed or // destroyed. virtual bool IsValid() = 0; + + // Set if the instance is deleted automatically when the window is destroyed + // by other ways. Default is true. virtual void SetDeleteThisOnDestroy(bool value) = 0; virtual void Close() = 0; - virtual NativeWindow* GetParent() = 0; + virtual INativeWindow* GetParent() = 0; virtual bool IsVisible() = 0; virtual void SetVisible(bool is_visible) = 0; @@ -64,16 +54,18 @@ class NativeWindow : public NativeResource { virtual bool CaptureMouse() = 0; virtual bool ReleaseMouse() = 0; - virtual void SetCursor(std::shared_ptr cursor) = 0; + virtual void SetCursor(std::shared_ptr cursor) = 0; + + virtual void RequestRepaint() = 0; - virtual void Repaint() = 0; - virtual graph::Painter* BeginPaint() = 0; + // Remember to call EndDraw on return value and destroy it. + virtual std::unique_ptr BeginPaint() = 0; virtual IEvent* DestroyEvent() = 0; virtual IEvent* PaintEvent() = 0; virtual IEvent* ResizeEvent() = 0; - virtual IEvent* FocusEvent() = 0; - virtual IEvent* MouseEnterLeaveEvent() = 0; + virtual IEvent* FocusEvent() = 0; + virtual IEvent* MouseEnterLeaveEvent() = 0; virtual IEvent* MouseMoveEvent() = 0; virtual IEvent* MouseDownEvent() = 0; virtual IEvent* MouseUpEvent() = 0; diff --git a/include/cru/platform/native/ui_application.hpp b/include/cru/platform/native/ui_application.hpp index 923fbaf7..6d2ab659 100644 --- a/include/cru/platform/native/ui_application.hpp +++ b/include/cru/platform/native/ui_application.hpp @@ -1,45 +1,36 @@ #pragma once #include "../native_resource.hpp" -#include "cursor.hpp" - #include #include #include namespace cru::platform::native { -class NativeWindow; +struct INativeWindow; +struct ICursorManager; // The entry point of a ui application. // It will call IGraphFactory::CreateInstance during its creation // and set graph factory to be auto deleted. If you want to keep // the graph factory then you should manually set it to false after // creating the ui application. -class UiApplication : public NativeResource { +struct IUiApplication : public virtual INativeResource { public: // Create a platform-specific instance and save it as the global instance. // Do not create the instance twice. Implements should assert for that. // After creating, get the instance by GetInstance. - static UiApplication* CreateInstance(); + static IUiApplication* CreateInstance(); // Get the global instance. If it is not created, then return nullptr. - static UiApplication* GetInstance(); - - protected: - UiApplication() = default; - - public: - UiApplication(const UiApplication& other) = delete; - UiApplication& operator=(const UiApplication& other) = delete; - - UiApplication(UiApplication&& other) = delete; - UiApplication& operator=(UiApplication&& other) = delete; - - ~UiApplication() override = default; + static IUiApplication* GetInstance(); public: + // Block current thread and run the message loop. Return the exit code when + // message loop gets a quit message (possibly posted by method RequestQuit). virtual int Run() = 0; - virtual void Quit(int quite_code) = 0; + + // Post a quit message with given quit code. + virtual void RequestQuit(int quit_code) = 0; virtual void AddOnQuitHandler(const std::function& handler) = 0; @@ -50,9 +41,9 @@ class UiApplication : public NativeResource { const std::function& action) = 0; virtual void CancelTimer(unsigned long id) = 0; - virtual std::vector GetAllWindow() = 0; - virtual NativeWindow* CreateWindow(NativeWindow* parent) = 0; + virtual std::vector GetAllWindow() = 0; + virtual INativeWindow* CreateWindow(INativeWindow* parent) = 0; - virtual CursorManager* GetCursorManager() = 0; + virtual ICursorManager* GetCursorManager() = 0; }; } // namespace cru::platform::native diff --git a/include/cru/platform/native_resource.hpp b/include/cru/platform/native_resource.hpp deleted file mode 100644 index ec7f01b6..00000000 --- a/include/cru/platform/native_resource.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "cru/common/base.hpp" - -#include - -namespace cru::platform { -class NativeResource : public Object { - protected: - NativeResource() = default; - - public: - NativeResource(const NativeResource& other) = delete; - NativeResource& operator=(const NativeResource& other) = delete; - - - NativeResource(NativeResource&& other) = delete; - NativeResource& operator=(NativeResource&& other) = delete; - ~NativeResource() override = default; - - public: - virtual std::wstring_view GetPlatformId() const = 0; -}; -} // namespace cru::platform diff --git a/include/cru/platform/resource.hpp b/include/cru/platform/resource.hpp new file mode 100644 index 00000000..6b315527 --- /dev/null +++ b/include/cru/platform/resource.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "cru/common/base.hpp" + +#include + +namespace cru::platform { +struct INativeResource : virtual Interface { + virtual std::string_view GetPlatformId() const = 0; +}; +} // namespace cru::platform diff --git a/include/cru/platform/string_util.hpp b/include/cru/platform/string_util.hpp deleted file mode 100644 index 822c0c95..00000000 --- a/include/cru/platform/string_util.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "cru/common/pre_config.hpp" - -#include -#include - -namespace cru::platform { -std::string ToUtf8String(const std::wstring_view& string); -} diff --git a/include/cru/ui/render/border_render_object.hpp b/include/cru/ui/render/border_render_object.hpp index e21ce34c..5520ab2e 100644 --- a/include/cru/ui/render/border_render_object.hpp +++ b/include/cru/ui/render/border_render_object.hpp @@ -7,7 +7,7 @@ namespace cru::platform::graph { class Brush; -class Geometry; +class IGeometry; } // namespace cru::platform::graph namespace cru::ui::render { @@ -131,11 +131,11 @@ class BorderRenderObject : public RenderObject { std::shared_ptr background_brush_; // The ring. Used for painting. - std::unique_ptr geometry_; + std::unique_ptr geometry_; // Area including inner area of the border. Used for painting foreground and // background. - std::unique_ptr border_inner_geometry_; + std::unique_ptr border_inner_geometry_; // Area including border ring and inner area. Used for hit test. - std::unique_ptr border_outer_geometry_; + std::unique_ptr border_outer_geometry_; }; } // namespace cru::ui::render diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp index f4cdefaa..4f44fed4 100644 --- a/include/cru/ui/window.hpp +++ b/include/cru/ui/window.hpp @@ -9,7 +9,7 @@ #include namespace cru::platform::native { -class NativeWindow; +class INativeWindow; } namespace cru::ui { @@ -43,7 +43,7 @@ class Window final : public ContentControl, public SelfResolvable { render::RenderObject* GetRenderObject() const override; - platform::native::NativeWindow* GetNativeWindow() const { + platform::native::INativeWindow* GetNativeWindow() const { return native_window_; } @@ -112,7 +112,7 @@ class Window final : public ContentControl, public SelfResolvable { void UpdateCursor(); private: - platform::native::NativeWindow* native_window_; + platform::native::INativeWindow* native_window_; std::vector event_revoker_guards_; std::shared_ptr render_object_; diff --git a/include/cru/win/graph/direct/brush.hpp b/include/cru/win/graph/direct/brush.hpp index 1f1c319f..0726ec3f 100644 --- a/include/cru/win/graph/direct/brush.hpp +++ b/include/cru/win/graph/direct/brush.hpp @@ -1,44 +1,39 @@ #pragma once #include "com_resource.hpp" -#include "direct_factory.hpp" -#include "platform_id.hpp" +#include "resource.hpp" #include "cru/platform/graph/brush.hpp" namespace cru::platform::graph::win::direct { -struct ID2DBrush { - virtual ~ID2DBrush() = default; - +struct ID2DBrush : virtual IBrush { virtual ID2D1Brush* GetD2DBrushInterface() const = 0; }; -class D2DSolidColorBrush : public SolidColorBrush, - public ID2DBrush, - public IComResource { +class D2DSolidColorBrush : public DirectGraphResource, + public virtual ISolidColorBrush, + public virtual ID2DBrush, + public virtual IComResource { public: - explicit D2DSolidColorBrush(IDirectFactory* factory); - - D2DSolidColorBrush(const D2DSolidColorBrush& other) = delete; - D2DSolidColorBrush& operator=(const D2DSolidColorBrush& other) = delete; + explicit D2DSolidColorBrush(DirectGraphFactory* factory); - D2DSolidColorBrush(D2DSolidColorBrush&& other) = delete; - D2DSolidColorBrush& operator=(D2DSolidColorBrush&& other) = delete; + CRU_DELETE_COPY(D2DSolidColorBrush) + CRU_DELETE_MOVE(D2DSolidColorBrush) ~D2DSolidColorBrush() override = default; - CRU_PLATFORMID_IMPLEMENT_DIRECT - public: + Color GetColor() override { return color_; } + void SetColor(const Color& color) override; + ID2D1Brush* GetD2DBrushInterface() const override { return brush_.Get(); } ID2D1SolidColorBrush* GetComInterface() const override { return brush_.Get(); } - protected: - void OnSetColor(const Color& color) override; - private: + Color color_ = colors::black; + Microsoft::WRL::ComPtr brush_; }; } // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/com_resource.hpp b/include/cru/win/graph/direct/com_resource.hpp index 22d1d6f0..a6c83434 100644 --- a/include/cru/win/graph/direct/com_resource.hpp +++ b/include/cru/win/graph/direct/com_resource.hpp @@ -1,11 +1,11 @@ #pragma once #include "../../win_pre_config.hpp" -namespace cru::platform::graph::win::direct { -template -struct IComResource { - virtual ~IComResource() = default; +#include "cru/common/base.hpp" +namespace cru::platform::graph::win::direct { +template +struct IComResource : virtual Interface { virtual TInterface* GetComInterface() const = 0; }; -} // namespace cru::platform::graph::win_direct +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/convert_util.hpp b/include/cru/win/graph/direct/convert_util.hpp index 2c45c63a..ef343a3f 100644 --- a/include/cru/win/graph/direct/convert_util.hpp +++ b/include/cru/win/graph/direct/convert_util.hpp @@ -1,8 +1,7 @@ #pragma once #include "../../win_pre_config.hpp" -#include "cru/platform/graphic_base.hpp" -#include "cru/platform/matrix.hpp" +#include "cru/platform/graph/base.hpp" namespace cru::platform::graph::win::direct { inline D2D1_MATRIX_3X2_F Convert(const platform::Matrix& matrix) { @@ -48,7 +47,7 @@ inline platform::Matrix Convert(const D2D1_MATRIX_3X2_F& matrix) { inline Color Convert(const D2D1_COLOR_F& color) { auto floor = [](float n) { return static_cast(n + 0.5f); }; return Color{floor(color.r * 255.0f), floor(color.g * 255.0f), - floor(color.b * 255.0f), floor(color.a * 255.0f)}; + floor(color.b * 255.0f), floor(color.a * 255.0f)}; } inline Point Convert(const D2D1_POINT_2F& point) { @@ -57,12 +56,12 @@ inline Point Convert(const D2D1_POINT_2F& point) { inline Rect Convert(const D2D1_RECT_F& rect) { return Rect(rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top); + rect.bottom - rect.top); } inline RoundedRect Convert(const D2D1_ROUNDED_RECT& rounded_rect) { return RoundedRect(Convert(rounded_rect.rect), rounded_rect.radiusX, - rounded_rect.radiusY); + rounded_rect.radiusY); } inline Ellipse Convert(const D2D1_ELLIPSE& ellipse) { diff --git a/include/cru/win/graph/direct/direct_factory.hpp b/include/cru/win/graph/direct/direct_factory.hpp deleted file mode 100644 index b150d5aa..00000000 --- a/include/cru/win/graph/direct/direct_factory.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../../win_pre_config.hpp" - -namespace cru::platform::graph::win::direct { -// Interface provides access to root d2d resources. -struct IDirectFactory { - virtual ~IDirectFactory() = default; - - virtual ID2D1Factory1* GetD2D1Factory() const = 0; - virtual ID2D1DeviceContext* GetD2D1DeviceContext() const = 0; - virtual ID3D11Device* GetD3D11Device() const = 0; - virtual IDXGIFactory2* GetDxgiFactory() const = 0; - virtual IDWriteFactory* GetDWriteFactory() const = 0; - virtual IDWriteFontCollection* GetSystemFontCollection() const = 0; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/factory.hpp b/include/cru/win/graph/direct/factory.hpp new file mode 100644 index 00000000..ae4eeb3a --- /dev/null +++ b/include/cru/win/graph/direct/factory.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "resource.hpp" + +#include "cru/platform/graph/factory.hpp" + +namespace cru::platform::graph::win::direct { +class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { + private: + DirectGraphFactory(); + + public: + CRU_DELETE_COPY(DirectGraphFactory) + CRU_DELETE_MOVE(DirectGraphFactory) + + ~DirectGraphFactory() override = default; + + public: + ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.Get(); } + ID2D1DeviceContext* GetD2D1DeviceContext() const { + return d2d1_device_context_.Get(); + } + ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } + IDXGIFactory2* GetDxgiFactory() const { return dxgi_factory_.Get(); } + IDWriteFactory* GetDWriteFactory() const { return dwrite_factory_.Get(); } + IDWriteFontCollection* GetSystemFontCollection() const { + return dwrite_system_font_collection_.Get(); + } + + public: + std::unique_ptr CreateSolidColorBrush() override; + + std::unique_ptr CreateGeometryBuilder() override; + + std::unique_ptr CreateFont(const std::string_view& font_family, + float font_size) override; + + std::unique_ptr CreateTextLayout(std::shared_ptr font, + std::string text) override; + + private: + Microsoft::WRL::ComPtr d3d11_device_; + Microsoft::WRL::ComPtr d2d1_factory_; + Microsoft::WRL::ComPtr d2d1_device_context_; + Microsoft::WRL::ComPtr dxgi_factory_; + Microsoft::WRL::ComPtr dwrite_factory_; + Microsoft::WRL::ComPtr dwrite_system_font_collection_; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/font.hpp b/include/cru/win/graph/direct/font.hpp index d3376503..08213ca5 100644 --- a/include/cru/win/graph/direct/font.hpp +++ b/include/cru/win/graph/direct/font.hpp @@ -1,31 +1,28 @@ #pragma once #include "com_resource.hpp" -#include "direct_factory.hpp" -#include "platform_id.hpp" +#include "resource.hpp" #include "cru/platform/graph/font.hpp" #include namespace cru::platform::graph::win::direct { - -class DWriteFont : public Font, public IComResource { +class DWriteFont : public DirectGraphResource, + public virtual IFont, + public virtual IComResource { public: - DWriteFont(IDirectFactory* factory, const std::wstring_view& font_family, + DWriteFont(DirectGraphFactory* factory, const std::string_view& font_family, float font_size); - DWriteFont(const DWriteFont& other) = delete; - DWriteFont& operator=(const DWriteFont& other) = delete; - - DWriteFont(DWriteFont&& other) = delete; - DWriteFont& operator=(DWriteFont&& other) = delete; + CRU_DELETE_COPY(DWriteFont) + CRU_DELETE_MOVE(DWriteFont) ~DWriteFont() override = default; - CRU_PLATFORMID_IMPLEMENT_DIRECT - public: - IDWriteTextFormat* GetComInterface() const override { return text_format_.Get(); } + IDWriteTextFormat* GetComInterface() const override { + return text_format_.Get(); + } private: Microsoft::WRL::ComPtr text_format_; diff --git a/include/cru/win/graph/direct/geometry.hpp b/include/cru/win/graph/direct/geometry.hpp index 1ee60247..086b31cc 100644 --- a/include/cru/win/graph/direct/geometry.hpp +++ b/include/cru/win/graph/direct/geometry.hpp @@ -1,26 +1,20 @@ #pragma once #include "com_resource.hpp" -#include "direct_factory.hpp" -#include "platform_id.hpp" +#include "resource.hpp" -#include "cru/platform/exception.hpp" #include "cru/platform/graph/geometry.hpp" namespace cru::platform::graph::win::direct { -class D2DGeometryBuilder : public GeometryBuilder { +class D2DGeometryBuilder : public DirectGraphResource, + public virtual IGeometryBuilder { public: - explicit D2DGeometryBuilder(IDirectFactory* factory); + explicit D2DGeometryBuilder(DirectGraphFactory* factory); - D2DGeometryBuilder(const D2DGeometryBuilder& other) = delete; - D2DGeometryBuilder& operator=(const D2DGeometryBuilder& other) = delete; - - D2DGeometryBuilder(D2DGeometryBuilder&& other) = delete; - D2DGeometryBuilder& operator=(D2DGeometryBuilder&& other) = delete; + CRU_DELETE_COPY(D2DGeometryBuilder) + CRU_DELETE_MOVE(D2DGeometryBuilder) ~D2DGeometryBuilder() override = default; - CRU_PLATFORMID_IMPLEMENT_DIRECT - public: void BeginFigure(const Point& point) override; void LineTo(const Point& point) override; @@ -28,34 +22,29 @@ class D2DGeometryBuilder : public GeometryBuilder { const Point& end_point) override; void CloseFigure(bool close) override; - Geometry* Build() override; + std::unique_ptr Build() override; private: bool IsValid() { return geometry_ != nullptr; } - void CheckValidation() { - if (!IsValid()) - throw ReuseException("The geometry builder is already disposed."); - } + void CheckValidation(); private: Microsoft::WRL::ComPtr geometry_; Microsoft::WRL::ComPtr geometry_sink_; }; -class D2DGeometry : public Geometry, public IComResource { +class D2DGeometry : public DirectGraphResource, + public virtual IGeometry, + public IComResource { public: - explicit D2DGeometry(Microsoft::WRL::ComPtr geometry); + D2DGeometry(DirectGraphFactory* factory, + Microsoft::WRL::ComPtr geometry); - D2DGeometry(const D2DGeometry& other) = delete; - D2DGeometry& operator=(const D2DGeometry& other) = delete; - - D2DGeometry(D2DGeometry&& other) = delete; - D2DGeometry& operator=(D2DGeometry&& other) = delete; + CRU_DELETE_COPY(D2DGeometry) + CRU_DELETE_MOVE(D2DGeometry) ~D2DGeometry() override = default; - CRU_PLATFORMID_IMPLEMENT_DIRECT - public: ID2D1Geometry* GetComInterface() const override { return geometry_.Get(); } diff --git a/include/cru/win/graph/direct/graph_factory.hpp b/include/cru/win/graph/direct/graph_factory.hpp deleted file mode 100644 index fb26a7c5..00000000 --- a/include/cru/win/graph/direct/graph_factory.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include "direct_factory.hpp" -#include "platform_id.hpp" - -#include "brush.hpp" -#include "font.hpp" -#include "geometry.hpp" -#include "text_layout.hpp" - -#include "cru/platform/graph/graph_factory.hpp" - -namespace cru::platform::graph::win::direct { -class DirectGraphFactory : public GraphFactory, public IDirectFactory { - friend GraphFactory* GraphFactory::CreateInstance(); - - public: - static DirectGraphFactory* GetInstance(); - - private: - DirectGraphFactory(); - - public: - DirectGraphFactory(const DirectGraphFactory& other) = delete; - DirectGraphFactory& operator=(const DirectGraphFactory& other) = delete; - - DirectGraphFactory(DirectGraphFactory&& other) = delete; - DirectGraphFactory& operator=(DirectGraphFactory&& other) = delete; - - ~DirectGraphFactory() override; - - CRU_PLATFORMID_IMPLEMENT_DIRECT - - public: - ID2D1Factory1* GetD2D1Factory() const override { return d2d1_factory_.Get(); } - ID2D1DeviceContext* GetD2D1DeviceContext() const override { - return d2d1_device_context_.Get(); - } - ID3D11Device* GetD3D11Device() const override { return d3d11_device_.Get(); } - IDXGIFactory2* GetDxgiFactory() const override { return dxgi_factory_.Get(); } - IDWriteFactory* GetDWriteFactory() const override { - return dwrite_factory_.Get(); - } - IDWriteFontCollection* GetSystemFontCollection() const override { - return dwrite_system_font_collection_.Get(); - } - - public: - D2DSolidColorBrush* CreateSolidColorBrush() override; - - D2DGeometryBuilder* CreateGeometryBuilder() override; - - DWriteFont* CreateFont(const std::wstring_view& font_family, - float font_size) override; - - DWriteTextLayout* CreateTextLayout(std::shared_ptr font, - std::wstring text) override; - - bool IsAutoDelete() const override { return auto_delete_; } - void SetAutoDelete(bool value) override { auto_delete_ = value; } - - private: - bool auto_delete_ = false; - - Microsoft::WRL::ComPtr d3d11_device_; - Microsoft::WRL::ComPtr d2d1_factory_; - Microsoft::WRL::ComPtr d2d1_device_context_; - Microsoft::WRL::ComPtr dxgi_factory_; - Microsoft::WRL::ComPtr dwrite_factory_; - Microsoft::WRL::ComPtr dwrite_system_font_collection_; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/painter.hpp b/include/cru/win/graph/direct/painter.hpp index d8791c7f..5a1fe03f 100644 --- a/include/cru/win/graph/direct/painter.hpp +++ b/include/cru/win/graph/direct/painter.hpp @@ -1,24 +1,21 @@ #pragma once #include "com_resource.hpp" -#include "platform_id.hpp" +#include "resource.hpp" #include "cru/platform/graph/painter.hpp" namespace cru::platform::graph::win::direct { -class D2DPainter : public Painter, public IComResource { +class D2DPainter : public DirectResource, + public virtual IPainter, + public virtual IComResource { public: explicit D2DPainter(ID2D1RenderTarget* render_target); - D2DPainter(const D2DPainter& other) = delete; - D2DPainter& operator=(const D2DPainter& other) = delete; - - D2DPainter(D2DPainter&& other) = delete; - D2DPainter& operator=(D2DPainter&& other) = delete; + CRU_DELETE_COPY(D2DPainter) + CRU_DELETE_MOVE(D2DPainter) ~D2DPainter() override = default; - CRU_PLATFORMID_IMPLEMENT_DIRECT - public: ID2D1RenderTarget* GetComInterface() const override { return render_target_; } @@ -28,15 +25,15 @@ class D2DPainter : public Painter, public IComResource { void Clear(const Color& color) override; - void StrokeRectangle(const Rect& rectangle, Brush* brush, + void StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) override; - void FillRectangle(const Rect& rectangle, Brush* brush) override; + void FillRectangle(const Rect& rectangle, IBrush* brush) override; - void StrokeGeometry(Geometry* geometry, Brush* brush, float width) override; - void FillGeometry(Geometry* geometry, Brush* brush) override; + void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; + void FillGeometry(IGeometry* geometry, IBrush* brush) override; - void DrawText(const Point& offset, TextLayout* text_layout, - Brush* brush) override; + void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) override; void EndDraw() override final; @@ -45,6 +42,7 @@ class D2DPainter : public Painter, public IComResource { private: bool IsValid() { return is_drawing_; } + void CheckValidation(); private: ID2D1RenderTarget* render_target_; diff --git a/include/cru/win/graph/direct/platform_id.hpp b/include/cru/win/graph/direct/platform_id.hpp deleted file mode 100644 index edac38f1..00000000 --- a/include/cru/win/graph/direct/platform_id.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include - -#include - -namespace cru::platform::graph::win::direct { -constexpr std::wstring_view win_direct_platform_id = L"Windows Direct"; - -inline bool IsDirectResource(NativeResource* resource) { - return resource->GetPlatformId() == win_direct_platform_id; -} - -} // namespace cru::platform::graph::win::direct - -#define CRU_PLATFORMID_IMPLEMENT_DIRECT \ - std::wstring_view GetPlatformId() const override { \ - return ::cru::platform::graph::win::direct::win_direct_platform_id; \ - } diff --git a/include/cru/win/graph/direct/resource.hpp b/include/cru/win/graph/direct/resource.hpp new file mode 100644 index 00000000..94a91a40 --- /dev/null +++ b/include/cru/win/graph/direct/resource.hpp @@ -0,0 +1,49 @@ +#pragma once +#include "../../win_pre_config.hpp" + +#include "cru/platform/graph/resource.hpp" + +#include + +namespace cru::platform::graph::win::direct { +class DirectGraphFactory; + +class DirectResource : public Object, public virtual INativeResource { + public: + static constexpr std::string_view k_platform_id = "Windows Direct"; + + protected: + DirectResource() = default; + + public: + CRU_DELETE_COPY(DirectResource) + CRU_DELETE_MOVE(DirectResource) + + ~DirectResource() override = default; + + public: + std::string_view GetPlatformId() const final { return k_platform_id; } +}; + +class DirectGraphResource : public DirectResource, + public virtual IGraphResource { + protected: + // Param factory can't be null. + explicit DirectGraphResource(DirectGraphFactory* factory); + + public: + CRU_DELETE_COPY(DirectGraphResource) + CRU_DELETE_MOVE(DirectGraphResource) + + ~DirectGraphResource() override = default; + + public: + IGraphFactory* GetGraphFactory() final; + + public: + DirectGraphFactory* GetDirectFactory() const { return factory_; } + + private: + DirectGraphFactory* factory_; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/text_layout.hpp b/include/cru/win/graph/direct/text_layout.hpp index a20591c2..5a8f3f9c 100644 --- a/include/cru/win/graph/direct/text_layout.hpp +++ b/include/cru/win/graph/direct/text_layout.hpp @@ -1,30 +1,25 @@ #pragma once #include "com_resource.hpp" -#include "direct_factory.hpp" -#include "platform_id.hpp" +#include "resource.hpp" #include "cru/platform/graph/text_layout.hpp" -#include "font.hpp" - #include namespace cru::platform::graph::win::direct { -class DWriteTextLayout : public TextLayout, - public IComResource { - public: - explicit DWriteTextLayout(IDirectFactory* factory, std::shared_ptr font, - std::wstring text); +class DWriteFont; - DWriteTextLayout(const DWriteTextLayout& other) = delete; - DWriteTextLayout& operator=(const DWriteTextLayout& other) = delete; - - DWriteTextLayout(DWriteTextLayout&& other) = delete; - DWriteTextLayout& operator=(DWriteTextLayout&& other) = delete; +class DWriteTextLayout : public DirectGraphResource, + public virtual ITextLayout, + public virtual IComResource { + public: + DWriteTextLayout(DirectGraphFactory* factory, std::shared_ptr font, + std::string text); - ~DWriteTextLayout() override = default; + CRU_DELETE_COPY(DWriteTextLayout) + CRU_DELETE_MOVE(DWriteTextLayout) - CRU_PLATFORMID_IMPLEMENT_DIRECT + ~DWriteTextLayout() override; public: IDWriteTextLayout* GetComInterface() const override { @@ -32,11 +27,11 @@ class DWriteTextLayout : public TextLayout, } public: - std::wstring GetText() override; - void SetText(std::wstring new_text) override; + std::string GetText() override; + void SetText(std::string new_text) override; - std::shared_ptr GetFont() override; - void SetFont(std::shared_ptr font) override; + std::shared_ptr GetFont() override; + void SetFont(std::shared_ptr font) override; void SetMaxWidth(float max_width) override; void SetMaxHeight(float max_height) override; @@ -45,8 +40,8 @@ class DWriteTextLayout : public TextLayout, std::vector TextRangeRect(const TextRange& text_range) override; private: - IDirectFactory* factory_; - std::wstring text_; + std::string text_; + std::wstring w_text_; std::shared_ptr font_; float max_width_ = 0.0f; float max_height_ = 0.0f; diff --git a/include/cru/win/native/native_window.hpp b/include/cru/win/native/native_window.hpp index cba5cc3e..16b14dbf 100644 --- a/include/cru/win/native/native_window.hpp +++ b/include/cru/win/native/native_window.hpp @@ -13,7 +13,7 @@ class WindowClass; class WindowManager; class WindowRenderTarget; -class WinNativeWindow : public NativeWindow { +class WinNativeWindow : public INativeWindow { public: WinNativeWindow(WinUiApplication* application, std::shared_ptr window_class, DWORD window_style, diff --git a/include/cru/win/native/platform_id.hpp b/include/cru/win/native/platform_id.hpp deleted file mode 100644 index e1899ad4..00000000 --- a/include/cru/win/native/platform_id.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include - -#include -#include - -namespace cru::platform::native::win { -constexpr std::wstring_view win_platform_id = L"Windows"; - -inline bool IsWindowsResource(NativeResource* resource) { - return resource->GetPlatformId() == win_platform_id; -} - -} // namespace cru::platform::native::win - -#define CRU_PLATFORMID_IMPLEMENT_WIN \ - std::wstring_view GetPlatformId() const override { \ - return ::cru::platform::native::win::win_platform_id; \ - } diff --git a/include/cru/win/native/ui_application.hpp b/include/cru/win/native/ui_application.hpp index addf2c93..94c4b1eb 100644 --- a/include/cru/win/native/ui_application.hpp +++ b/include/cru/win/native/ui_application.hpp @@ -44,8 +44,8 @@ class WinUiApplication : public UiApplication { const std::function& action) override; void CancelTimer(unsigned long id) override; - std::vector GetAllWindow() override; - NativeWindow* CreateWindow(NativeWindow* parent) override; + std::vector GetAllWindow() override; + INativeWindow* CreateWindow(INativeWindow* parent) override; WinCursorManager* GetCursorManager() override; diff --git a/include/cru/win/string.hpp b/include/cru/win/string.hpp new file mode 100644 index 00000000..7a12e47e --- /dev/null +++ b/include/cru/win/string.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "win_pre_config.hpp" + +#include +#include + +namespace cru::platform::win { +std::string ToUtf8String(const std::wstring_view& string); +std::wstring ToUtf16String(const std::string_view& string); +} diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index afbbc139..516d5f1b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -2,7 +2,7 @@ set(CRU_BASE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/common) add_library(cru_base STATIC logger.cpp ) -target_sources(cru_base INTERFACE +target_sources(cru_base PUBLIC ${CRU_BASE_INCLUDE_DIR}/base.hpp ${CRU_BASE_INCLUDE_DIR}/event.hpp ${CRU_BASE_INCLUDE_DIR}/format.hpp diff --git a/src/common/logger.cpp b/src/common/logger.cpp index 25223d91..6c1422f9 100644 --- a/src/common/logger.cpp +++ b/src/common/logger.cpp @@ -2,6 +2,7 @@ #include "cru/common/format.hpp" +#include #include #include #include @@ -11,7 +12,7 @@ namespace cru::log { namespace { Logger *CreateLogger() { const auto logger = new Logger(); - logger->AddSource(new StdioLoggerSource()); + logger->AddSource(std::make_unique()); return logger; } } // namespace @@ -21,45 +22,45 @@ Logger *Logger::GetInstance() { return logger.get(); } -Logger::~Logger() { - for (const auto i : sources_) { - delete i; - } +void Logger::AddSource(std::unique_ptr source) { + sources_.push_back(std::move(source)); } -void Logger::AddSource(ILoggerSource *source) { sources_.push_back(source); } - -void Logger::RemoveSource(ILoggerSource *source) { sources_.remove(source); } +void Logger::RemoveSource(ILogSource *source) { + sources_.remove_if([source](const std::unique_ptr &s) { + return s.get() == source; + }); +} namespace { -std::wstring_view LogLevelToString(LogLevel level) { +std::string_view LogLevelToString(LogLevel level) { switch (level) { case LogLevel::Debug: - return L"DEBUG"; + return "DEBUG"; case LogLevel::Info: - return L"INFO"; + return "INFO"; case LogLevel::Warn: - return L"WARN"; + return "WARN"; case LogLevel::Error: - return L"ERROR"; + return "ERROR"; default: std::abort(); } } } // namespace -void Logger::Log(LogLevel level, const std::wstring_view &s) { +void Logger::Log(LogLevel level, const std::string_view &s) { #ifndef CRU_DEBUG if (level == LogLevel::Debug) { return; } #endif - for (const auto source : sources_) { + for (const auto &source : sources_) { auto now = std::time(nullptr); - wchar_t buffer[50]; - std::wcsftime(buffer, 50, L"%c", std::localtime(&now)); + std::array buffer; + std::strftime(buffer.data(), 50, "%c", std::localtime(&now)); - source->Write(level, util::Format(L"[{}] {}: {}\n", buffer, + source->Write(level, util::Format("[{}] {}: {}\n", buffer.data(), LogLevelToString(level), s)); } } diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index c9eef482..01952106 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -1,12 +1,12 @@ set(CRU_PLATFORM_BASE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform) add_library(cru_platform_base INTERFACE) target_sources(cru_platform_base INTERFACE + ${CRU_PLATFORM_BASE_INCLUDE_DIR}/check.hpp ${CRU_PLATFORM_BASE_INCLUDE_DIR}/exception.hpp - ${CRU_PLATFORM_BASE_INCLUDE_DIR}/graphic_base.hpp + ${CRU_PLATFORM_BASE_INCLUDE_DIR}/graph_base.hpp ${CRU_PLATFORM_BASE_INCLUDE_DIR}/heap_debug.hpp ${CRU_PLATFORM_BASE_INCLUDE_DIR}/matrix.hpp - ${CRU_PLATFORM_BASE_INCLUDE_DIR}/native_resource.hpp - ${CRU_PLATFORM_BASE_INCLUDE_DIR}/string_util.hpp + ${CRU_PLATFORM_BASE_INCLUDE_DIR}/resource.hpp ) target_link_libraries(cru_platform_base INTERFACE cru_base) diff --git a/src/platform/graph/CMakeLists.txt b/src/platform/graph/CMakeLists.txt index da76d296..dac28370 100644 --- a/src/platform/graph/CMakeLists.txt +++ b/src/platform/graph/CMakeLists.txt @@ -1,12 +1,14 @@ set(CRU_PLATFORM_GRAPH_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform/graph) add_library(cru_platform_graph INTERFACE) target_sources(cru_platform_graph INTERFACE + ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/base.hpp ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/brush.hpp ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/font.hpp ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/geometry.hpp - ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/graph_factory.hpp + ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/factory.hpp + ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/resource.hpp ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/painter.hpp ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/text_layout.hpp - ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/util/painter_util.hpp + ${CRU_PLATFORM_GRAPH_INCLUDE_DIR}/util/painter.hpp ) target_link_libraries(cru_platform_graph INTERFACE cru_platform_base) diff --git a/src/platform/native/CMakeLists.txt b/src/platform/native/CMakeLists.txt index 0e44fd55..bc7c4a63 100644 --- a/src/platform/native/CMakeLists.txt +++ b/src/platform/native/CMakeLists.txt @@ -1,12 +1,10 @@ set(CRU_PLATFORM_NATIVE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform/native) -add_library(cru_platform_native STATIC - cursor.cpp -) -target_sources(cru_platform_native PUBLIC +add_library(cru_platform_native INTERFACE) +target_sources(cru_platform_native INTERFACE ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/basic_types.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/cursor.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/native_event.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/native_window.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/ui_application.hpp ) -target_link_libraries(cru_platform_native PUBLIC cru_platform_graph) +target_link_libraries(cru_platform_native INTERFACE cru_platform_graph) diff --git a/src/platform/native/cursor.cpp b/src/platform/native/cursor.cpp deleted file mode 100644 index b12aec40..00000000 --- a/src/platform/native/cursor.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "cru/platform/native/cursor.hpp" - -#include "cru/platform/native/ui_application.hpp" - -namespace cru::platform::native { -std::shared_ptr GetSystemCursor(SystemCursor type) { - return UiApplication::GetInstance()->GetCursorManager()->GetSystemCursor( - type); -} -} // namespace cru::platform::native diff --git a/src/win/CMakeLists.txt b/src/win/CMakeLists.txt index 8c58954d..5727e4c0 100644 --- a/src/win/CMakeLists.txt +++ b/src/win/CMakeLists.txt @@ -5,10 +5,11 @@ add_library(cru_win_base STATIC exception.cpp heap_debug.cpp - string_util.cpp + string.cpp ) target_sources(cru_win_base PUBLIC ${CRU_WIN_BASE_INCLUDE_DIR}/exception.hpp + ${CRU_WIN_BASE_INCLUDE_DIR}/string.hpp ${CRU_WIN_BASE_INCLUDE_DIR}/win_pre_config.hpp ) target_compile_definitions(cru_win_base PUBLIC UNICODE _UNICODE) # use unicode diff --git a/src/win/debug_logger.hpp b/src/win/debug_logger.hpp index ab6a2266..53c4859b 100644 --- a/src/win/debug_logger.hpp +++ b/src/win/debug_logger.hpp @@ -4,7 +4,7 @@ namespace cru::platform::win { -class WinDebugLoggerSource : public ::cru::log::ILoggerSource { +class WinDebugLoggerSource : public ::cru::log::ILogSource { public: WinDebugLoggerSource() = default; @@ -13,8 +13,8 @@ class WinDebugLoggerSource : public ::cru::log::ILoggerSource { ~WinDebugLoggerSource() = default; - void Write(::cru::log::LogLevel level, const std::wstring_view& s) override { - ::OutputDebugStringW(s.data()); + void Write(::cru::log::LogLevel level, const std::string_view& s) override { + ::OutputDebugStringA(s.data()); } }; } // namespace cru::platform::win diff --git a/src/win/graph/direct/CMakeLists.txt b/src/win/graph/direct/CMakeLists.txt index fa5e3a99..b277fa32 100644 --- a/src/win/graph/direct/CMakeLists.txt +++ b/src/win/graph/direct/CMakeLists.txt @@ -4,21 +4,21 @@ add_library(cru_win_graph_direct STATIC brush.cpp font.cpp geometry.cpp - graph_factory.cpp + factory.cpp painter.cpp + resource.cpp text_layout.cpp ) target_sources(cru_win_graph_direct PUBLIC ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/brush.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/com_resource.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/convert_util.hpp - ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/direct_factory.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/exception.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/font.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/geometry.hpp - ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/graph_factory.hpp + ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/factory.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/painter.hpp - ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/platform_id.hpp + ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/resource.hpp ${CRU_WIN_GRAPH_DIRECT_INCLUDE_DIR}/text_layout.hpp ) target_link_libraries(cru_win_graph_direct PUBLIC D3D11 D2d1 DWrite cru_win_base cru_platform_graph) diff --git a/src/win/graph/direct/brush.cpp b/src/win/graph/direct/brush.cpp index 1f17cd03..17024a66 100644 --- a/src/win/graph/direct/brush.cpp +++ b/src/win/graph/direct/brush.cpp @@ -2,17 +2,18 @@ #include "cru/win/graph/direct/convert_util.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" #include namespace cru::platform::graph::win::direct { -D2DSolidColorBrush::D2DSolidColorBrush(IDirectFactory* factory) { - assert(factory); +D2DSolidColorBrush::D2DSolidColorBrush(DirectGraphFactory* factory) + : DirectGraphResource(factory) { ThrowIfFailed(factory->GetD2D1DeviceContext()->CreateSolidColorBrush( Convert(color_), &brush_)); } -void D2DSolidColorBrush::OnSetColor(const Color& color) { +void D2DSolidColorBrush::SetColor(const Color& color) { brush_->SetColor(Convert(color)); } } // namespace cru::platform::graph::win::direct diff --git a/src/win/graph/direct/factory.cpp b/src/win/graph/direct/factory.cpp new file mode 100644 index 00000000..7882c3ee --- /dev/null +++ b/src/win/graph/direct/factory.cpp @@ -0,0 +1,79 @@ +#include "cru/win/graph/direct/factory.hpp" + +#include "cru/win/graph/direct/brush.hpp" +#include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/font.hpp" +#include "cru/win/graph/direct/geometry.hpp" +#include "cru/win/graph/direct/text_layout.hpp" + +#include +#include +#include + +namespace cru::platform::graph::win::direct { +DirectGraphFactory::DirectGraphFactory() { + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#ifdef CRU_DEBUG + creation_flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + const D3D_FEATURE_LEVEL feature_levels[] = { + D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1}; + + Microsoft::WRL::ComPtr d3d11_device_context; + + ThrowIfFailed(D3D11CreateDevice( + nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, creation_flags, + feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, + &d3d11_device_, nullptr, &d3d11_device_context)); + + Microsoft::WRL::ComPtr dxgi_device; + ThrowIfFailed(d3d11_device_->QueryInterface(dxgi_device.GetAddressOf())); + + ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + IID_PPV_ARGS(&d2d1_factory_))); + + Microsoft::WRL::ComPtr d2d1_device; + + ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device)); + + ThrowIfFailed(d2d1_device->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context_)); + + // Identify the physical adapter (GPU or card) this device is runs on. + Microsoft::WRL::ComPtr dxgi_adapter; + ThrowIfFailed(dxgi_device->GetAdapter(&dxgi_adapter)); + + // Get the factory object that created the DXGI device. + ThrowIfFailed(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory_))); + + ThrowIfFailed(DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + reinterpret_cast(dwrite_factory_.GetAddressOf()))); + + ThrowIfFailed(dwrite_factory_->GetSystemFontCollection( + &dwrite_system_font_collection_)); +} + +std::unique_ptr DirectGraphFactory::CreateSolidColorBrush() { + return std::make_unique(this); +} + +std::unique_ptr DirectGraphFactory::CreateGeometryBuilder() { + return std::make_unique(this); +} + +std::unique_ptr DirectGraphFactory::CreateFont( + const std::string_view& font_family, float font_size) { + return std::make_unique(this, font_family, font_size); +} + +std::unique_ptr DirectGraphFactory::CreateTextLayout( + std::shared_ptr font, std::string text) { + return std::make_unique(this, std::move(font), + std::move(text)); +} +} // namespace cru::platform::graph::win::direct diff --git a/src/win/graph/direct/font.cpp b/src/win/graph/direct/font.cpp index 5d7b4483..8e881f84 100644 --- a/src/win/graph/direct/font.cpp +++ b/src/win/graph/direct/font.cpp @@ -1,25 +1,29 @@ #include "cru/win/graph/direct/font.hpp" -#include "cru/win/exception.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" +#include "cru/win/string.hpp" #include #include #include namespace cru::platform::graph::win::direct { -DWriteFont::DWriteFont(IDirectFactory* factory, - const std::wstring_view& font_family, float font_size) { - assert(factory); +DWriteFont::DWriteFont(DirectGraphFactory* factory, + const std::string_view& font_family, float font_size) + : DirectGraphResource(factory) { + // Get locale std::array buffer; if (!::GetUserDefaultLocaleName(buffer.data(), static_cast(buffer.size()))) - throw platform::win::Win32Error(::GetLastError(), "Failed to get locale."); + throw platform::win::Win32Error( + ::GetLastError(), "Failed to get locale when create dwrite font."); + + const std::wstring&& wff = cru::platform::win::ToUtf16String(font_family); ThrowIfFailed(factory->GetDWriteFactory()->CreateTextFormat( - font_family.data(), nullptr, DWRITE_FONT_WEIGHT_NORMAL, - DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, font_size, - buffer.data(), &text_format_)); + wff.data(), nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, font_size, buffer.data(), &text_format_)); ThrowIfFailed(text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); ThrowIfFailed( diff --git a/src/win/graph/direct/geometry.cpp b/src/win/graph/direct/geometry.cpp index 470addee..5540edab 100644 --- a/src/win/graph/direct/geometry.cpp +++ b/src/win/graph/direct/geometry.cpp @@ -2,16 +2,22 @@ #include "cru/win/graph/direct/convert_util.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" #include namespace cru::platform::graph::win::direct { -D2DGeometryBuilder::D2DGeometryBuilder(IDirectFactory* factory) { - assert(factory); +D2DGeometryBuilder::D2DGeometryBuilder(DirectGraphFactory* factory) + : DirectGraphResource(factory) { ThrowIfFailed(factory->GetD2D1Factory()->CreatePathGeometry(&geometry_)); ThrowIfFailed(geometry_->Open(&geometry_sink_)); } +void D2DGeometryBuilder::CheckValidation() { + if (!IsValid()) + throw ReuseException("The geometry builder is already disposed."); +} + void D2DGeometryBuilder::BeginFigure(const Point& point) { CheckValidation(); geometry_sink_->BeginFigure(Convert(point), D2D1_FIGURE_BEGIN_FILLED); @@ -35,19 +41,19 @@ void D2DGeometryBuilder::CloseFigure(bool close) { : D2D1_FIGURE_END_OPEN); } -Geometry* D2DGeometryBuilder::Build() { +std::unique_ptr D2DGeometryBuilder::Build() { CheckValidation(); ThrowIfFailed(geometry_sink_->Close()); geometry_sink_ = nullptr; - const auto geometry = new D2DGeometry(std::move(geometry_)); + auto geometry = + std::make_unique(GetDirectFactory(), std::move(geometry_)); geometry_ = nullptr; return geometry; } -D2DGeometry::D2DGeometry(Microsoft::WRL::ComPtr geometry) { - assert(geometry); - geometry_ = std::move(geometry); -} +D2DGeometry::D2DGeometry(DirectGraphFactory* factory, + Microsoft::WRL::ComPtr geometry) + : DirectGraphResource(factory), geometry_(std::move(geometry)) {} bool D2DGeometry::FillContains(const Point& point) { BOOL result; diff --git a/src/win/graph/direct/graph_factory.cpp b/src/win/graph/direct/graph_factory.cpp deleted file mode 100644 index 49752d0b..00000000 --- a/src/win/graph/direct/graph_factory.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "cru/win/graph/direct/graph_factory.hpp" - -#include "cru/win/graph/direct/brush.hpp" -#include "cru/win/graph/direct/exception.hpp" -#include "cru/win/graph/direct/font.hpp" -#include "cru/win/graph/direct/geometry.hpp" -#include "cru/win/graph/direct/text_layout.hpp" - -#include -#include -#include - -namespace cru::platform::graph::win::direct { -namespace { -DirectGraphFactory* instance = nullptr; -} -} // namespace cru::platform::graph::win::direct - -namespace cru::platform::graph { -void GraphFactoryAutoDeleteExitHandler() { - const auto i = - ::cru::platform::graph::win::direct::instance; // avoid long namespace - // prefix - if (i == nullptr) return; - if (i->IsAutoDelete()) delete i; -} - -GraphFactory* GraphFactory::CreateInstance() { - auto& i = ::cru::platform::graph::win::direct::instance; // avoid long - // namespace prefix - assert(i == nullptr); - i = new ::cru::platform::graph::win::direct::DirectGraphFactory(); - std::atexit(&GraphFactoryAutoDeleteExitHandler); - return i; -} - -GraphFactory* GraphFactory::GetInstance() { - return ::cru::platform::graph::win::direct::instance; -} -} // namespace cru::platform::graph - -namespace cru::platform::graph::win::direct { -DirectGraphFactory* DirectGraphFactory::GetInstance() { return instance; } - -DirectGraphFactory::DirectGraphFactory() { - UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; - -#ifdef CRU_DEBUG - creation_flags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - - const D3D_FEATURE_LEVEL feature_levels[] = { - D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1}; - - Microsoft::WRL::ComPtr d3d11_device_context; - - ThrowIfFailed(D3D11CreateDevice( - nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, creation_flags, - feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, - &d3d11_device_, nullptr, &d3d11_device_context)); - - Microsoft::WRL::ComPtr dxgi_device; - ThrowIfFailed(d3d11_device_->QueryInterface(dxgi_device.GetAddressOf())); - - ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, - IID_PPV_ARGS(&d2d1_factory_))); - - Microsoft::WRL::ComPtr d2d1_device; - - ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device)); - - ThrowIfFailed(d2d1_device->CreateDeviceContext( - D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context_)); - - // Identify the physical adapter (GPU or card) this device is runs on. - Microsoft::WRL::ComPtr dxgi_adapter; - ThrowIfFailed(dxgi_device->GetAdapter(&dxgi_adapter)); - - // Get the factory object that created the DXGI device. - ThrowIfFailed(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory_))); - - ThrowIfFailed(DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(dwrite_factory_.GetAddressOf()))); - - ThrowIfFailed(dwrite_factory_->GetSystemFontCollection( - &dwrite_system_font_collection_)); -} - -DirectGraphFactory::~DirectGraphFactory() { instance = nullptr; } - -D2DSolidColorBrush* DirectGraphFactory::CreateSolidColorBrush() { - return new D2DSolidColorBrush(this); -} - -D2DGeometryBuilder* DirectGraphFactory::CreateGeometryBuilder() { - return new D2DGeometryBuilder(this); -} - -DWriteFont* DirectGraphFactory::CreateFont( - const std::wstring_view& font_family, float font_size) { - return new DWriteFont(this, font_family, font_size); -} - -DWriteTextLayout* DirectGraphFactory::CreateTextLayout( - std::shared_ptr font, std::wstring text) { - return new DWriteTextLayout(this, std::move(font), std::move(text)); -} -} // namespace cru::platform::graph::win::direct diff --git a/src/win/graph/direct/painter.cpp b/src/win/graph/direct/painter.cpp index 6fbbf957..fb2a6e7f 100644 --- a/src/win/graph/direct/painter.cpp +++ b/src/win/graph/direct/painter.cpp @@ -1,5 +1,6 @@ #include "cru/win/graph/direct/painter.hpp" +#include "cru/platform/check.hpp" #include "cru/win/graph/direct/brush.hpp" #include "cru/win/graph/direct/convert_util.hpp" #include "cru/win/graph/direct/exception.hpp" @@ -10,89 +11,63 @@ #include namespace cru::platform::graph::win::direct { - -namespace { -template -struct is_static_castable : std::false_type {}; - -template -struct is_static_castable< - T, U, std::void_t(std::declval()))>> - : std::true_type {}; - -template -TDes* CheckAndCast(TSrc* src) { - assert(src); - assert(IsDirectResource(src)); - if constexpr (is_static_castable::value) - return static_cast(src); - else { - TDes* d = dynamic_cast(src); - assert(d); - return d; - } -} -} // namespace - D2DPainter::D2DPainter(ID2D1RenderTarget* render_target) { assert(render_target); render_target_ = render_target; } platform::Matrix D2DPainter::GetTransform() { - assert(IsValid()); + CheckValidation(); D2D1_MATRIX_3X2_F m; render_target_->GetTransform(&m); return Convert(m); } void D2DPainter::SetTransform(const platform::Matrix& matrix) { - assert(IsValid()); + CheckValidation(); render_target_->SetTransform(Convert(matrix)); } void D2DPainter::Clear(const Color& color) { - assert(IsValid()); + CheckValidation(); render_target_->Clear(Convert(color)); } -void D2DPainter::StrokeRectangle(const Rect& rectangle, Brush* brush, +void D2DPainter::StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) { - assert(IsValid()); - const auto b = CheckAndCast(brush); + CheckValidation(); + const auto b = CheckPlatform(brush, GetPlatformId()); render_target_->DrawRectangle(Convert(rectangle), b->GetD2DBrushInterface(), width); } -void D2DPainter::FillRectangle(const Rect& rectangle, Brush* brush) { - assert(IsValid()); - const auto b = CheckAndCast(brush); +void D2DPainter::FillRectangle(const Rect& rectangle, IBrush* brush) { + CheckValidation(); + const auto b = CheckPlatform(brush, GetPlatformId()); render_target_->FillRectangle(Convert(rectangle), b->GetD2DBrushInterface()); } -void D2DPainter::StrokeGeometry(Geometry* geometry, Brush* brush, float width) { - assert(IsValid()); - const auto g = CheckAndCast(geometry); - const auto b = CheckAndCast(brush); - +void D2DPainter::StrokeGeometry(IGeometry* geometry, IBrush* brush, + float width) { + CheckValidation(); + const auto g = CheckPlatform(geometry, GetPlatformId()); + const auto b = CheckPlatform(brush, GetPlatformId()); render_target_->DrawGeometry(g->GetComInterface(), b->GetD2DBrushInterface(), width); } -void D2DPainter::FillGeometry(Geometry* geometry, Brush* brush) { - assert(IsValid()); - const auto g = CheckAndCast(geometry); - const auto b = CheckAndCast(brush); - +void D2DPainter::FillGeometry(IGeometry* geometry, IBrush* brush) { + CheckValidation(); + const auto g = CheckPlatform(geometry, GetPlatformId()); + const auto b = CheckPlatform(brush, GetPlatformId()); render_target_->FillGeometry(g->GetComInterface(), b->GetD2DBrushInterface()); } -void D2DPainter::DrawText(const Point& offset, TextLayout* text_layout, - Brush* brush) { - assert(IsValid()); - const auto t = CheckAndCast(text_layout); - const auto b = CheckAndCast(brush); - +void D2DPainter::DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) { + CheckValidation(); + const auto t = CheckPlatform(text_layout, GetPlatformId()); + const auto b = CheckPlatform(brush, GetPlatformId()); render_target_->DrawTextLayout(Convert(offset), t->GetComInterface(), b->GetD2DBrushInterface()); } @@ -103,4 +78,11 @@ void D2DPainter::EndDraw() { DoEndDraw(); } } + +void D2DPainter::CheckValidation() { + if (!is_drawing_) { + throw cru::platform::ReuseException( + "Can't do that on painter after end drawing."); + } +} } // namespace cru::platform::graph::win::direct diff --git a/src/win/graph/direct/resource.cpp b/src/win/graph/direct/resource.cpp new file mode 100644 index 00000000..2acc91e4 --- /dev/null +++ b/src/win/graph/direct/resource.cpp @@ -0,0 +1,14 @@ +#include "cru/win/graph/direct/resource.hpp" + +#include "cru/win/graph/direct/factory.hpp" + +#include + +namespace cru::platform::graph::win::direct { +DirectGraphResource::DirectGraphResource(DirectGraphFactory* factory) + : factory_(factory) { + assert(factory); +} + +IGraphFactory* DirectGraphResource::GetGraphFactory() { return factory_; } +} // namespace cru::platform::graph::win::direct diff --git a/src/win/graph/direct/text_layout.cpp b/src/win/graph/direct/text_layout.cpp index 23a14b2a..a1750799 100644 --- a/src/win/graph/direct/text_layout.cpp +++ b/src/win/graph/direct/text_layout.cpp @@ -1,46 +1,49 @@ #include "cru/win/graph/direct/text_layout.hpp" +#include "cru/platform/check.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" +#include "cru/win/graph/direct/font.hpp" +#include "cru/win/string.hpp" #include #include namespace cru::platform::graph::win::direct { -DWriteTextLayout::DWriteTextLayout(IDirectFactory* factory, - std::shared_ptr font, - std::wstring text) - : text_(std::move(text)) { - assert(factory); +DWriteTextLayout::DWriteTextLayout(DirectGraphFactory* factory, + std::shared_ptr font, + std::string text) + : DirectGraphResource(factory), text_(std::move(text)) { assert(font); - assert(IsDirectResource(font.get())); - factory_ = factory; - font_ = std::static_pointer_cast(font); + font_ = CheckPlatform(font, GetPlatformId()); + + w_text_ = cru::platform::win::ToUtf16String(text_); ThrowIfFailed(factory->GetDWriteFactory()->CreateTextLayout( - text_.c_str(), static_cast(text_.size()), + w_text_.c_str(), static_cast(w_text_.size()), font_->GetComInterface(), max_width_, max_height_, &text_layout_)); } -std::wstring DWriteTextLayout::GetText() { return text_; } +DWriteTextLayout::~DWriteTextLayout() = default; + +std::string DWriteTextLayout::GetText() { return text_; } -void DWriteTextLayout::SetText(std::wstring new_text) { +void DWriteTextLayout::SetText(std::string new_text) { text_.swap(new_text); - ThrowIfFailed(factory_->GetDWriteFactory()->CreateTextLayout( - text_.c_str(), static_cast(text_.size()), + w_text_ = cru::platform::win::ToUtf16String(text_); + ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout( + w_text_.c_str(), static_cast(w_text_.size()), font_->GetComInterface(), max_width_, max_height_, &text_layout_)); } -std::shared_ptr DWriteTextLayout::GetFont() { - return std::static_pointer_cast(font_); +std::shared_ptr DWriteTextLayout::GetFont() { + return std::dynamic_pointer_cast(font_); } -void DWriteTextLayout::SetFont(std::shared_ptr font) { - assert(IsDirectResource(font.get())); - auto f = std::static_pointer_cast(font); - - f.swap(font_); - ThrowIfFailed(factory_->GetDWriteFactory()->CreateTextLayout( - text_.c_str(), static_cast(text_.size()), +void DWriteTextLayout::SetFont(std::shared_ptr font) { + font_ = CheckPlatform(font, GetPlatformId()); + ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout( + w_text_.c_str(), static_cast(w_text_.size()), font_->GetComInterface(), max_width_, max_height_, &text_layout_)); } diff --git a/src/win/native/CMakeLists.txt b/src/win/native/CMakeLists.txt index 08acc739..0e7e5b4e 100644 --- a/src/win/native/CMakeLists.txt +++ b/src/win/native/CMakeLists.txt @@ -22,7 +22,6 @@ target_sources(cru_win_native PUBLIC ${CRU_WIN_NATIVE_INCLUDE_DIR}/exception.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/god_window.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/native_window.hpp - ${CRU_WIN_NATIVE_INCLUDE_DIR}/platform_id.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/ui_application.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/window_class.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/window_native_message_event_args.hpp diff --git a/src/win/native/ui_application.cpp b/src/win/native/ui_application.cpp index c2d3ac2c..0bbe9c03 100644 --- a/src/win/native/ui_application.cpp +++ b/src/win/native/ui_application.cpp @@ -107,16 +107,16 @@ void WinUiApplication::CancelTimer(unsigned long id) { timer_manager_->KillTimer(static_cast(id)); } -std::vector WinUiApplication::GetAllWindow() { +std::vector WinUiApplication::GetAllWindow() { const auto&& windows = window_manager_->GetAllWindows(); - std::vector result; + std::vector result; for (const auto w : windows) { - result.push_back(static_cast(w)); + result.push_back(static_cast(w)); } return result; } -NativeWindow* WinUiApplication::CreateWindow(NativeWindow* parent) { +INativeWindow* WinUiApplication::CreateWindow(INativeWindow* parent) { WinNativeWindow* p = nullptr; if (parent != nullptr) { p = dynamic_cast(parent); diff --git a/src/win/string.cpp b/src/win/string.cpp new file mode 100644 index 00000000..84906f6b --- /dev/null +++ b/src/win/string.cpp @@ -0,0 +1,46 @@ +#include "cru/win/string.hpp" + +#include "cru/win/exception.hpp" + +namespace cru::platform::win { +std::string ToUtf8String(const std::wstring_view& string) { + if (string.empty()) return std::string{}; + + const auto length = + ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), -1, + nullptr, 0, nullptr, nullptr); + if (length == 0) { + throw Win32Error(::GetLastError(), + "Failed to convert wide string to UTF-8."); + } + + std::string result; + result.resize(length); + if (::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), -1, + result.data(), static_cast(result.size()), + nullptr, nullptr) == 0) + throw Win32Error(::GetLastError(), + "Failed to convert wide string to UTF-8."); + return result; +} + +std::wstring ToUtf16String(const std::string_view& string) { + if (string.empty()) return std::wstring{}; + + const auto length = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + string.data(), -1, nullptr, 0); + if (length == 0) { + throw Win32Error(::GetLastError(), + "Failed to convert wide string to UTF-16."); + } + + std::wstring result; + result.resize(length); + if (::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, string.data(), -1, + result.data(), + static_cast(result.size())) == 0) + throw win::Win32Error(::GetLastError(), + "Failed to convert wide string to UTF-16."); + return result; +} +} // namespace cru::platform::win diff --git a/src/win/string_util.cpp b/src/win/string_util.cpp deleted file mode 100644 index dd513b12..00000000 --- a/src/win/string_util.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "cru/platform/string_util.hpp" - -#include "cru/win/exception.hpp" - -namespace cru::platform { -std::string ToUtf8String(const std::wstring_view& string) { - if (string.empty()) return std::string(); - - const auto length = ::WideCharToMultiByte(CP_UTF8, 0, string.data(), -1, - nullptr, 0, nullptr, nullptr); - std::string result; - result.resize(length); - if (::WideCharToMultiByte(CP_UTF8, 0, string.data(), -1, result.data(), - static_cast(result.size()), nullptr, - nullptr) == 0) - throw win::Win32Error(::GetLastError(), - "Failed to convert wide string to UTF-8."); - return result; -} -} // namespace cru::platform -- cgit v1.2.3