diff options
author | crupest <crupest@outlook.com> | 2022-01-12 23:13:10 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-12 23:13:10 +0800 |
commit | 276ae73fa444c16f34a379ae9d8f58c883056b4a (patch) | |
tree | 96f4d7103976836e918b4fa1db0fdbb80777986e | |
parent | 01f98ce88950cdb729f5db58bf26f2fffa1c326c (diff) | |
parent | 65c799c5339ba37bea2217b168e96b15aceaef85 (diff) | |
download | cru-276ae73fa444c16f34a379ae9d8f58c883056b4a.tar.gz cru-276ae73fa444c16f34a379ae9d8f58c883056b4a.tar.bz2 cru-276ae73fa444c16f34a379ae9d8f58c883056b4a.zip |
Merge pull request #44 from crupest/dev
Windows development.
75 files changed, 643 insertions, 275 deletions
diff --git a/include/cru/common/PropertyTree.hpp b/include/cru/common/PropertyTree.hpp index 01b50dac..613bcc47 100644 --- a/include/cru/common/PropertyTree.hpp +++ b/include/cru/common/PropertyTree.hpp @@ -8,7 +8,7 @@ namespace cru { class PropertyTree; -class PropertySubTreeRef { +class CRU_BASE_API PropertySubTreeRef { public: static String CombineKey(StringView left, StringView right); @@ -37,7 +37,7 @@ class PropertySubTreeRef { String path_; }; -class PropertyTree { +class CRU_BASE_API PropertyTree { public: static String CombineKey(StringView left, StringView right); diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 8acb6a87..dd3da52f 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -80,6 +80,8 @@ class CRU_BASE_API String { } } + String(size_type size, value_type ch = 0); + String(std::initializer_list<value_type> l); explicit String(StringView str); @@ -328,16 +330,16 @@ std::enable_if_t<std::is_integral_v<T>, String> ToString(T value) { auto result = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value); + if (result.ec == std::errc{}) { + } else { + throw std::invalid_argument("Failed to convert value to chars."); + } + auto size = result.ptr - buffer.data(); auto b = new char16_t[size + 1]; b[size] = 0; std::copy(buffer.data(), result.ptr, b); return String::FromBuffer(b, size, size); - - if (result.ec == std::errc{}) { - } else { - throw std::invalid_argument("Failed to convert value to chars."); - } } template <typename T> @@ -346,7 +348,7 @@ std::enable_if_t<std::is_floating_point_v<T>, String> ToString(T value) { return String(str.cbegin(), str.cend()); } -inline String ToString(String value) { return std::move(value); } +inline String ToString(String value) { return value; } namespace details { enum class FormatTokenType { PlaceHolder, Text }; @@ -366,7 +368,7 @@ template <typename TA, typename... T> void FormatAppendFromFormatTokenList( String& current, const std::vector<FormatToken>& format_token_list, Index index, TA&& args0, T&&... args) { - for (Index i = index; i < format_token_list.size(); i++) { + for (Index i = index; i < static_cast<Index>(format_token_list.size()); i++) { const auto& token = format_token_list[i]; if (token.type == FormatTokenType::PlaceHolder) { current += ToString(std::forward<TA>(args0)); diff --git a/include/cru/common/StringUtil.hpp b/include/cru/common/StringUtil.hpp index a0cb6b0b..27ad4b43 100644 --- a/include/cru/common/StringUtil.hpp +++ b/include/cru/common/StringUtil.hpp @@ -49,7 +49,7 @@ class CodePointIterator { struct past_end_tag_t {}; explicit CodePointIterator(const CharType* ptr, Index size, Index current = 0) - : ptr_(ptr), size_(size), position_(0) {} + : ptr_(ptr), size_(size), position_(current) {} explicit CodePointIterator(const CharType* ptr, Index size, past_end_tag_t) : ptr_(ptr), size_(size), position_(size) {} diff --git a/include/cru/osx/graphics/quartz/Painter.hpp b/include/cru/osx/graphics/quartz/Painter.hpp index 0889d413..83f15516 100644 --- a/include/cru/osx/graphics/quartz/Painter.hpp +++ b/include/cru/osx/graphics/quartz/Painter.hpp @@ -40,8 +40,7 @@ class QuartzCGContextPainter : public OsxQuartzResource, void FillRectangle(const Rect& rectangle, IBrush* brush) override; void StrokeEllipse(const Rect& outline_rect, IBrush* brush, float width) override; - void FillEllipse(const Rect& outline_rect, IBrush* brush, - float width) override; + void FillEllipse(const Rect& outline_rect, IBrush* brush) override; void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; void FillGeometry(IGeometry* geometry, IBrush* brush) override; diff --git a/include/cru/parse/Base.hpp b/include/cru/parse/Base.hpp new file mode 100644 index 00000000..8f3a05e9 --- /dev/null +++ b/include/cru/parse/Base.hpp @@ -0,0 +1,11 @@ +#pragma once + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_PARSE_EXPORT_API +#define CRU_PARSE_API __declspec(dllexport) +#else +#define CRU_PARSE_API __declspec(dllimport) +#endif +#else +#define CRU_PARSE_API +#endif diff --git a/include/cru/parse/Grammar.hpp b/include/cru/parse/Grammar.hpp index 606fcc33..8dc1833f 100644 --- a/include/cru/parse/Grammar.hpp +++ b/include/cru/parse/Grammar.hpp @@ -5,7 +5,7 @@ #include <vector> namespace cru::parse { -class Grammar : public Object { +class CRU_PARSE_API Grammar : public Object { public: Grammar(); diff --git a/include/cru/parse/Nonterminal.hpp b/include/cru/parse/Nonterminal.hpp index 1bc6f9ff..b01c7c8a 100644 --- a/include/cru/parse/Nonterminal.hpp +++ b/include/cru/parse/Nonterminal.hpp @@ -2,7 +2,7 @@ #include "Symbol.hpp" namespace cru::parse { -class Nonterminal : public Symbol { +class CRU_PARSE_API Nonterminal : public Symbol { public: Nonterminal(Grammar* grammar, String name); diff --git a/include/cru/parse/ParsingAlgorithm.hpp b/include/cru/parse/ParsingAlgorithm.hpp index acca159e..8f38c0ab 100644 --- a/include/cru/parse/ParsingAlgorithm.hpp +++ b/include/cru/parse/ParsingAlgorithm.hpp @@ -7,7 +7,7 @@ class ParsingAlgorithmContext; // Represents a parsing algorithm. // It does not relate to any specific grammar. // It is used to validate a grammar and create a parsing algorithm context. -class ParsingAlgorithm { +class CRU_PARSE_API ParsingAlgorithm { public: ParsingAlgorithm() = default; diff --git a/include/cru/parse/ParsingAlgorithmContext.hpp b/include/cru/parse/ParsingAlgorithmContext.hpp index f67ccbbc..b959462c 100644 --- a/include/cru/parse/ParsingAlgorithmContext.hpp +++ b/include/cru/parse/ParsingAlgorithmContext.hpp @@ -10,7 +10,7 @@ class ParsingAlgorithm; // A parsing algorithm context contains all data a parsing algorithm needs to // parse for a grammar. It does not relate to any input. For example, it can // contain any state machine. -class ParsingAlgorithmContext { +class CRU_PARSE_API ParsingAlgorithmContext { public: ParsingAlgorithmContext(Grammar* grammar, const ParsingAlgorithm* algorithm); diff --git a/include/cru/parse/ParsingContext.hpp b/include/cru/parse/ParsingContext.hpp index ebb7115a..cfb850b9 100644 --- a/include/cru/parse/ParsingContext.hpp +++ b/include/cru/parse/ParsingContext.hpp @@ -5,7 +5,7 @@ namespace cru::parse { // A parsing context contains all info that a program needs to know when parsing // a input sequence of terminals. -class ParsingContext { +class CRU_PARSE_API ParsingContext { public: ParsingContext(const ParsingAlgorithmContext* parsing_algorithm_context, std::vector<Terminal*> input); diff --git a/include/cru/parse/ParsingTreeNode.hpp b/include/cru/parse/ParsingTreeNode.hpp index d1c3d058..7119ca0b 100644 --- a/include/cru/parse/ParsingTreeNode.hpp +++ b/include/cru/parse/ParsingTreeNode.hpp @@ -4,7 +4,7 @@ #include <vector> namespace cru::parse { -class ParsingTreeNode { +class CRU_PARSE_API ParsingTreeNode { public: ParsingTreeNode(Symbol* symbol, Production* production); diff --git a/include/cru/parse/Production.hpp b/include/cru/parse/Production.hpp index 8a1331b9..cb3c79c0 100644 --- a/include/cru/parse/Production.hpp +++ b/include/cru/parse/Production.hpp @@ -7,7 +7,7 @@ #include <vector> namespace cru::parse { -class Production : public Object { +class CRU_PARSE_API Production : public Object { public: Production(Grammar* grammar, String name, Nonterminal* left, std::vector<Symbol*> right); diff --git a/include/cru/parse/RecursiveDescentAlgorithm.hpp b/include/cru/parse/RecursiveDescentAlgorithm.hpp index c12a84f6..373724ea 100644 --- a/include/cru/parse/RecursiveDescentAlgorithm.hpp +++ b/include/cru/parse/RecursiveDescentAlgorithm.hpp @@ -3,7 +3,7 @@ #include "ParsingAlgorithm.hpp" namespace cru::parse { -class RecursiveDescentAlgorithm : public ParsingAlgorithm { +class CRU_PARSE_API RecursiveDescentAlgorithm : public ParsingAlgorithm { public: RecursiveDescentAlgorithm() = default; diff --git a/include/cru/parse/RecursiveDescentAlgorithmContext.hpp b/include/cru/parse/RecursiveDescentAlgorithmContext.hpp index 1b888da9..b29ee1a1 100644 --- a/include/cru/parse/RecursiveDescentAlgorithmContext.hpp +++ b/include/cru/parse/RecursiveDescentAlgorithmContext.hpp @@ -6,7 +6,7 @@ #include "cru/parse/Terminal.hpp" namespace cru::parse { -class RecursiveDescentAlgorithmContext : public ParsingAlgorithmContext { +class CRU_PARSE_API RecursiveDescentAlgorithmContext : public ParsingAlgorithmContext { public: RecursiveDescentAlgorithmContext(Grammar* grammar, const RecursiveDescentAlgorithm* algorithm); diff --git a/include/cru/parse/Symbol.hpp b/include/cru/parse/Symbol.hpp index e22fb9bc..7404a5e7 100644 --- a/include/cru/parse/Symbol.hpp +++ b/include/cru/parse/Symbol.hpp @@ -1,11 +1,13 @@ #pragma once +#include "Base.hpp" + #include "cru/common/String.hpp" namespace cru::parse { class Grammar; // Base class of Terminal and Nonterminal. -class Symbol : public Object { +class CRU_PARSE_API Symbol : public Object { public: explicit Symbol(Grammar* grammar, String name); diff --git a/include/cru/parse/Terminal.hpp b/include/cru/parse/Terminal.hpp index 8d4a31b6..4ff8f898 100644 --- a/include/cru/parse/Terminal.hpp +++ b/include/cru/parse/Terminal.hpp @@ -2,7 +2,7 @@ #include "Symbol.hpp" namespace cru::parse { -class Terminal : public Symbol { +class CRU_PARSE_API Terminal : public Symbol { public: Terminal(Grammar* grammar, String name); diff --git a/include/cru/parse/TokenType.hpp b/include/cru/parse/TokenType.hpp index 54bdf712..49415d3b 100644 --- a/include/cru/parse/TokenType.hpp +++ b/include/cru/parse/TokenType.hpp @@ -1,9 +1,11 @@ #pragma once +#include "Base.hpp" + #include "cru/common/Base.hpp" #include "cru/common/String.hpp" namespace cru::parse { -class TokenType : public Object { +class CRU_PARSE_API TokenType : public Object { public: explicit TokenType(String name); diff --git a/include/cru/platform/graphics/Base.hpp b/include/cru/platform/graphics/Base.hpp index 26ae725a..3a18e39d 100644 --- a/include/cru/platform/graphics/Base.hpp +++ b/include/cru/platform/graphics/Base.hpp @@ -6,6 +6,17 @@ #include <memory> +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_PLATFORM_GRAPHICS_EXPORT_API +#define CRU_PLATFORM_GRAPHICS_API __declspec(dllexport) +#else +#define CRU_PLATFORM_GRAPHICS_API __declspec(dllimport) +#endif +#else +#define CRU_PLATFORM_GRAPHICS_API +#endif + + namespace cru::platform::graphics { // forward declarations struct IGraphicsFactory; diff --git a/include/cru/platform/graphics/Brush.hpp b/include/cru/platform/graphics/Brush.hpp index aa21f79d..772edd5c 100644 --- a/include/cru/platform/graphics/Brush.hpp +++ b/include/cru/platform/graphics/Brush.hpp @@ -2,9 +2,9 @@ #include "Resource.hpp" namespace cru::platform::graphics { -struct IBrush : virtual IGraphicsResource {}; +struct CRU_PLATFORM_GRAPHICS_API IBrush : virtual IGraphicsResource {}; -struct ISolidColorBrush : virtual IBrush { +struct CRU_PLATFORM_GRAPHICS_API ISolidColorBrush : virtual IBrush { virtual Color GetColor() = 0; virtual void SetColor(const Color& color) = 0; }; diff --git a/include/cru/platform/graphics/Factory.hpp b/include/cru/platform/graphics/Factory.hpp index b79e1c4f..f3802651 100644 --- a/include/cru/platform/graphics/Factory.hpp +++ b/include/cru/platform/graphics/Factory.hpp @@ -8,7 +8,7 @@ namespace cru::platform::graphics { // Entry point of the graphics module. -struct IGraphicsFactory : virtual IPlatformResource { +struct CRU_PLATFORM_GRAPHICS_API IGraphicsFactory : virtual IPlatformResource { virtual std::unique_ptr<ISolidColorBrush> CreateSolidColorBrush() = 0; virtual std::unique_ptr<IGeometryBuilder> CreateGeometryBuilder() = 0; diff --git a/include/cru/platform/graphics/Font.hpp b/include/cru/platform/graphics/Font.hpp index e1a419eb..2d1bc9a6 100644 --- a/include/cru/platform/graphics/Font.hpp +++ b/include/cru/platform/graphics/Font.hpp @@ -2,7 +2,7 @@ #include "Resource.hpp" namespace cru::platform::graphics { -struct IFont : virtual IGraphicsResource { +struct CRU_PLATFORM_GRAPHICS_API IFont : virtual IGraphicsResource { virtual float GetFontSize() = 0; }; } // namespace cru::platform::graphics diff --git a/include/cru/platform/graphics/Geometry.hpp b/include/cru/platform/graphics/Geometry.hpp index f01132fb..e83d1c51 100644 --- a/include/cru/platform/graphics/Geometry.hpp +++ b/include/cru/platform/graphics/Geometry.hpp @@ -2,13 +2,13 @@ #include "Resource.hpp" namespace cru::platform::graphics { -struct IGeometry : virtual IGraphicsResource { +struct CRU_PLATFORM_GRAPHICS_API IGeometry : virtual IGraphicsResource { virtual bool FillContains(const Point& point) = 0; }; // After called Build, calling every method will throw a -struct IGeometryBuilder : virtual IGraphicsResource { +struct CRU_PLATFORM_GRAPHICS_API IGeometryBuilder : virtual IGraphicsResource { virtual void BeginFigure(const Point& point) = 0; virtual void LineTo(const Point& point) = 0; virtual void QuadraticBezierTo(const Point& control_point, diff --git a/include/cru/platform/graphics/NullPainter.hpp b/include/cru/platform/graphics/NullPainter.hpp index cf790ccf..b5c796d3 100644 --- a/include/cru/platform/graphics/NullPainter.hpp +++ b/include/cru/platform/graphics/NullPainter.hpp @@ -1,8 +1,9 @@ #pragma once #include "Painter.hpp" +#include "cru/common/Base.hpp" namespace cru::platform::graphics { -class NullPainter : public Object, public virtual IPainter { +class CRU_PLATFORM_GRAPHICS_API NullPainter : public Object, public virtual IPainter { public: NullPainter() = default; @@ -17,30 +18,54 @@ class NullPainter : public Object, public virtual IPainter { String GetDebugString() override { return u"NullPainter"; } Matrix GetTransform() override { return Matrix(); } - void SetTransform(const Matrix& matrix) override {} + void SetTransform(const Matrix& matrix) override { CRU_UNUSED(matrix) } - void ConcatTransform(const Matrix& matrix) override {} + void ConcatTransform(const Matrix& matrix) override { CRU_UNUSED(matrix) } - void Clear(const Color& color) override {} + void Clear(const Color& color) override { CRU_UNUSED(color) } void DrawLine(const Point& start, const Point& end, IBrush* brush, - float width) override{}; + float width) override { + CRU_UNUSED(start) CRU_UNUSED(end) CRU_UNUSED(brush) CRU_UNUSED(width) + } void StrokeRectangle(const Rect& rectangle, IBrush* brush, - float width) override {} - void FillRectangle(const Rect& rectangle, IBrush* brush) override {} + float width) override { + CRU_UNUSED(rectangle) CRU_UNUSED(brush) CRU_UNUSED(width) + } + void FillRectangle(const Rect& rectangle, IBrush* brush) override { + CRU_UNUSED(rectangle) + CRU_UNUSED(brush) + } void StrokeEllipse(const Rect& outline_rect, IBrush* brush, - float width) override {} - void FillEllipse(const Rect& outline_rect, IBrush* brush, - float width) override {} + float width) override { + CRU_UNUSED(outline_rect) + CRU_UNUSED(brush) + CRU_UNUSED(width) + } + void FillEllipse(const Rect& outline_rect, IBrush* brush) override { + CRU_UNUSED(outline_rect) + CRU_UNUSED(brush) + } void StrokeGeometry(IGeometry* geometry, IBrush* brush, - float width) override {} - void FillGeometry(IGeometry* geometry, IBrush* brush) override {} + float width) override { + CRU_UNUSED(geometry) + CRU_UNUSED(brush) + CRU_UNUSED(width) + } + void FillGeometry(IGeometry* geometry, IBrush* brush) override { + CRU_UNUSED(geometry) + CRU_UNUSED(brush) + } void DrawText(const Point& offset, ITextLayout* text_layout, - IBrush* brush) override {} + IBrush* brush) override { + CRU_UNUSED(offset) + CRU_UNUSED(text_layout) + CRU_UNUSED(brush) + } - void PushLayer(const Rect& bounds) override{}; + void PushLayer(const Rect& bounds) override { CRU_UNUSED(bounds) } void PopLayer() override {} diff --git a/include/cru/platform/graphics/Painter.hpp b/include/cru/platform/graphics/Painter.hpp index 4f1724ec..4104a752 100644 --- a/include/cru/platform/graphics/Painter.hpp +++ b/include/cru/platform/graphics/Painter.hpp @@ -3,7 +3,7 @@ namespace cru::platform::graphics { -struct IPainter : virtual IPlatformResource { +struct CRU_PLATFORM_GRAPHICS_API IPainter : virtual IPlatformResource { virtual Matrix GetTransform() = 0; virtual void SetTransform(const Matrix& matrix) = 0; @@ -18,8 +18,7 @@ struct IPainter : virtual IPlatformResource { virtual void FillRectangle(const Rect& rectangle, IBrush* brush) = 0; virtual void StrokeEllipse(const Rect& outline_rect, IBrush* brush, float width) = 0; - virtual void FillEllipse(const Rect& outline_rect, IBrush* brush, - float width) = 0; + virtual void FillEllipse(const Rect& outline_rect, IBrush* brush) = 0; virtual void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) = 0; diff --git a/include/cru/platform/graphics/Resource.hpp b/include/cru/platform/graphics/Resource.hpp index cd1e5283..e559b0e9 100644 --- a/include/cru/platform/graphics/Resource.hpp +++ b/include/cru/platform/graphics/Resource.hpp @@ -4,7 +4,7 @@ namespace cru::platform::graphics { struct IGraphicsFactory; -struct IGraphicsResource : virtual IPlatformResource { +struct CRU_PLATFORM_GRAPHICS_API IGraphicsResource : virtual IPlatformResource { virtual IGraphicsFactory* GetGraphicsFactory() = 0; }; } // namespace cru::platform::graphics diff --git a/include/cru/platform/graphics/TextLayout.hpp b/include/cru/platform/graphics/TextLayout.hpp index a040ec3b..f9ccc824 100644 --- a/include/cru/platform/graphics/TextLayout.hpp +++ b/include/cru/platform/graphics/TextLayout.hpp @@ -7,7 +7,7 @@ namespace cru::platform::graphics { // Requirement: // All text must be left-top aligned. -struct ITextLayout : virtual IGraphicsResource { +struct CRU_PLATFORM_GRAPHICS_API ITextLayout : virtual IGraphicsResource { virtual String GetText() = 0; virtual void SetText(String new_text) = 0; diff --git a/include/cru/platform/gui/Window.hpp b/include/cru/platform/gui/Window.hpp index bab5e8fe..9f17b976 100644 --- a/include/cru/platform/gui/Window.hpp +++ b/include/cru/platform/gui/Window.hpp @@ -85,7 +85,6 @@ struct INativeWindow : virtual IPlatformResource { // Remember to call EndDraw on return value and destroy it. virtual std::unique_ptr<graphics::IPainter> BeginPaint() = 0; - // Don't use this instance after receive this event. virtual IEvent<std::nullptr_t>* CreateEvent() = 0; virtual IEvent<std::nullptr_t>* DestroyEvent() = 0; virtual IEvent<std::nullptr_t>* PaintEvent() = 0; diff --git a/include/cru/toml/Base.hpp b/include/cru/toml/Base.hpp new file mode 100644 index 00000000..de1d558c --- /dev/null +++ b/include/cru/toml/Base.hpp @@ -0,0 +1,11 @@ +#pragma once + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_TOML_EXPORT_API +#define CRU_TOML_API __declspec(dllexport) +#else +#define CRU_TOML_API __declspec(dllimport) +#endif +#else +#define CRU_TOML_API +#endif diff --git a/include/cru/toml/TomlDocument.hpp b/include/cru/toml/TomlDocument.hpp index 637690f7..1e5caf71 100644 --- a/include/cru/toml/TomlDocument.hpp +++ b/include/cru/toml/TomlDocument.hpp @@ -1,5 +1,7 @@ #pragma once +#include "Base.hpp" + #include "cru/common/Base.hpp" #include "cru/common/String.hpp" @@ -7,7 +9,7 @@ #include <unordered_map> namespace cru::toml { -class TomlSection { +class CRU_TOML_API TomlSection { public: CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(TomlSection) CRU_DEFAULT_COPY(TomlSection) @@ -29,7 +31,7 @@ class TomlSection { std::unordered_map<String, String> values_; }; -class TomlDocument { +class CRU_TOML_API TomlDocument { public: CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(TomlDocument) CRU_DEFAULT_COPY(TomlDocument) diff --git a/include/cru/toml/TomlParser.hpp b/include/cru/toml/TomlParser.hpp index 52332506..c3091bad 100644 --- a/include/cru/toml/TomlParser.hpp +++ b/include/cru/toml/TomlParser.hpp @@ -7,12 +7,12 @@ namespace cru::toml { // A very simple and tolerant TOML parser. -class TomlParsingException : public Exception { +class CRU_TOML_API TomlParsingException : public Exception { public: using Exception::Exception; }; -class TomlParser { +class CRU_TOML_API TomlParser { public: explicit TomlParser(String input); diff --git a/include/cru/win/WinPreConfig.hpp b/include/cru/win/WinPreConfig.hpp index 1613da95..1bd494f2 100644 --- a/include/cru/win/WinPreConfig.hpp +++ b/include/cru/win/WinPreConfig.hpp @@ -8,6 +8,7 @@ #undef CreateWindow #undef DrawText #undef CreateFont +#undef CreateEvent #include <d2d1_2.h> #include <d3d11.h> diff --git a/include/cru/win/graphics/direct/Brush.hpp b/include/cru/win/graphics/direct/Brush.hpp index fbff83b5..9d8e5384 100644 --- a/include/cru/win/graphics/direct/Brush.hpp +++ b/include/cru/win/graphics/direct/Brush.hpp @@ -9,12 +9,12 @@ struct ID2DBrush : virtual IBrush { virtual ID2D1Brush* GetD2DBrushInterface() const = 0; }; -class D2DSolidColorBrush : public DirectGraphResource, +class D2DSolidColorBrush : public DirectGraphicsResource, public virtual ISolidColorBrush, public virtual ID2DBrush, public virtual IComResource<ID2D1SolidColorBrush> { public: - explicit D2DSolidColorBrush(DirectGraphFactory* factory); + explicit D2DSolidColorBrush(DirectGraphicsFactory* factory); CRU_DELETE_COPY(D2DSolidColorBrush) CRU_DELETE_MOVE(D2DSolidColorBrush) diff --git a/include/cru/win/graphics/direct/Factory.hpp b/include/cru/win/graphics/direct/Factory.hpp index 70f3ede1..efcebba7 100644 --- a/include/cru/win/graphics/direct/Factory.hpp +++ b/include/cru/win/graphics/direct/Factory.hpp @@ -4,14 +4,15 @@ #include "cru/platform/graphics/Factory.hpp" namespace cru::platform::graphics::win::direct { -class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { +class DirectGraphicsFactory : public DirectResource, + public virtual IGraphicsFactory { public: - DirectGraphFactory(); + DirectGraphicsFactory(); - CRU_DELETE_COPY(DirectGraphFactory) - CRU_DELETE_MOVE(DirectGraphFactory) + CRU_DELETE_COPY(DirectGraphicsFactory) + CRU_DELETE_MOVE(DirectGraphicsFactory) - ~DirectGraphFactory() override; + ~DirectGraphicsFactory() override; public: ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } @@ -38,11 +39,11 @@ class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { std::unique_ptr<IGeometryBuilder> CreateGeometryBuilder() override; - std::unique_ptr<IFont> CreateFont(std::u16string font_family, + std::unique_ptr<IFont> CreateFont(String font_family, float font_size) override; std::unique_ptr<ITextLayout> CreateTextLayout(std::shared_ptr<IFont> font, - std::u16string text) override; + String text) override; private: Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; diff --git a/include/cru/win/graphics/direct/Font.hpp b/include/cru/win/graphics/direct/Font.hpp index fd3921a3..3cd94f82 100644 --- a/include/cru/win/graphics/direct/Font.hpp +++ b/include/cru/win/graphics/direct/Font.hpp @@ -7,11 +7,11 @@ #include <string_view> namespace cru::platform::graphics::win::direct { -class DWriteFont : public DirectGraphResource, +class DWriteFont : public DirectGraphicsResource, public virtual IFont, public virtual IComResource<IDWriteTextFormat> { public: - DWriteFont(DirectGraphFactory* factory, std::u16string font_family, + DWriteFont(DirectGraphicsFactory* factory, String font_family, float font_size); CRU_DELETE_COPY(DWriteFont) @@ -27,7 +27,7 @@ class DWriteFont : public DirectGraphResource, float GetFontSize() override; private: - std::u16string font_family_; + String font_family_; Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_; }; } // namespace cru::platform::graphics::win::direct diff --git a/include/cru/win/graphics/direct/Geometry.hpp b/include/cru/win/graphics/direct/Geometry.hpp index edfec590..b3b82f9c 100644 --- a/include/cru/win/graphics/direct/Geometry.hpp +++ b/include/cru/win/graphics/direct/Geometry.hpp @@ -5,10 +5,10 @@ #include "cru/platform/graphics/Geometry.hpp" namespace cru::platform::graphics::win::direct { -class D2DGeometryBuilder : public DirectGraphResource, +class D2DGeometryBuilder : public DirectGraphicsResource, public virtual IGeometryBuilder { public: - explicit D2DGeometryBuilder(DirectGraphFactory* factory); + explicit D2DGeometryBuilder(DirectGraphicsFactory* factory); CRU_DELETE_COPY(D2DGeometryBuilder) CRU_DELETE_MOVE(D2DGeometryBuilder) @@ -33,11 +33,11 @@ class D2DGeometryBuilder : public DirectGraphResource, Microsoft::WRL::ComPtr<ID2D1GeometrySink> geometry_sink_; }; -class D2DGeometry : public DirectGraphResource, +class D2DGeometry : public DirectGraphicsResource, public virtual IGeometry, public IComResource<ID2D1Geometry> { public: - D2DGeometry(DirectGraphFactory* factory, + D2DGeometry(DirectGraphicsFactory* factory, Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry); CRU_DELETE_COPY(D2DGeometry) diff --git a/include/cru/win/graphics/direct/Painter.hpp b/include/cru/win/graphics/direct/Painter.hpp index b34c1563..d7b90d19 100644 --- a/include/cru/win/graphics/direct/Painter.hpp +++ b/include/cru/win/graphics/direct/Painter.hpp @@ -24,6 +24,7 @@ class D2DPainter : public DirectResource, public: Matrix GetTransform() override; void SetTransform(const platform::Matrix& matrix) override; + void ConcatTransform(const Matrix& matrix) override; void Clear(const Color& color) override; @@ -32,6 +33,9 @@ class D2DPainter : public DirectResource, void StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) override; void FillRectangle(const Rect& rectangle, IBrush* brush) override; + void StrokeEllipse(const Rect& outline_rect, IBrush* brush, + float width) override; + void FillEllipse(const Rect& outline_rect, IBrush* brush) override; void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; void FillGeometry(IGeometry* geometry, IBrush* brush) override; @@ -40,9 +44,11 @@ class D2DPainter : public DirectResource, IBrush* brush) override; void PushLayer(const Rect& bounds) override; - void PopLayer() override; + void PushState() override; + void PopState() override; + void EndDraw() override final; protected: @@ -56,6 +62,8 @@ class D2DPainter : public DirectResource, ID2D1RenderTarget* render_target_; std::vector<Microsoft::WRL::ComPtr<ID2D1Layer>> layers_; + std::vector<Microsoft::WRL::ComPtr<ID2D1DrawingStateBlock>> + drawing_state_stack_; bool is_drawing_ = true; }; diff --git a/include/cru/win/graphics/direct/Resource.hpp b/include/cru/win/graphics/direct/Resource.hpp index e6ffb203..c376628d 100644 --- a/include/cru/win/graphics/direct/Resource.hpp +++ b/include/cru/win/graphics/direct/Resource.hpp @@ -6,7 +6,7 @@ #include <string_view> namespace cru::platform::graphics::win::direct { -class DirectGraphFactory; +class DirectGraphicsFactory; class DirectResource : public Object, public virtual IPlatformResource { public: @@ -25,25 +25,25 @@ class DirectResource : public Object, public virtual IPlatformResource { String GetPlatformId() const final { return kPlatformId; } }; -class DirectGraphResource : public DirectResource, - public virtual IGraphResource { +class DirectGraphicsResource : public DirectResource, + public virtual IGraphicsResource { protected: // Param factory can't be null. - explicit DirectGraphResource(DirectGraphFactory* factory); + explicit DirectGraphicsResource(DirectGraphicsFactory* factory); public: - CRU_DELETE_COPY(DirectGraphResource) - CRU_DELETE_MOVE(DirectGraphResource) + CRU_DELETE_COPY(DirectGraphicsResource) + CRU_DELETE_MOVE(DirectGraphicsResource) - ~DirectGraphResource() override = default; + ~DirectGraphicsResource() override = default; public: - IGraphFactory* GetGraphFactory() final; + IGraphicsFactory* GetGraphicsFactory() final; public: - DirectGraphFactory* GetDirectFactory() const { return factory_; } + DirectGraphicsFactory* GetDirectFactory() const { return factory_; } private: - DirectGraphFactory* factory_; + DirectGraphicsFactory* factory_; }; } // namespace cru::platform::graphics::win::direct diff --git a/include/cru/win/graphics/direct/TextLayout.hpp b/include/cru/win/graphics/direct/TextLayout.hpp index aa040278..b1843dd7 100644 --- a/include/cru/win/graphics/direct/TextLayout.hpp +++ b/include/cru/win/graphics/direct/TextLayout.hpp @@ -10,12 +10,12 @@ namespace cru::platform::graphics::win::direct { class DWriteFont; -class DWriteTextLayout : public DirectGraphResource, +class DWriteTextLayout : public DirectGraphicsResource, public virtual ITextLayout, public virtual IComResource<IDWriteTextLayout> { public: - DWriteTextLayout(DirectGraphFactory* factory, std::shared_ptr<IFont> font, - std::u16string text); + DWriteTextLayout(DirectGraphicsFactory* factory, std::shared_ptr<IFont> font, + String text); CRU_DELETE_COPY(DWriteTextLayout) CRU_DELETE_MOVE(DWriteTextLayout) @@ -28,9 +28,8 @@ class DWriteTextLayout : public DirectGraphResource, } public: - std::u16string GetText() override; - std::u16string_view GetTextView() override; - void SetText(std::u16string new_text) override; + String GetText() override; + void SetText(String new_text) override; std::shared_ptr<IFont> GetFont() override; void SetFont(std::shared_ptr<IFont> font) override; @@ -38,15 +37,23 @@ class DWriteTextLayout : public DirectGraphResource, void SetMaxWidth(float max_width) override; void SetMaxHeight(float max_height) override; + bool IsEditMode() override; + void SetEditMode(bool enable) override; + + Index GetLineIndexFromCharIndex(Index char_index) override; + float GetLineHeight(Index line_index) override; + Index GetLineCount() override; + Rect GetTextBounds(bool includingTrailingSpace = false) override; // Return empty vector if text_range.count is 0. Text range could be in // reverse direction, it should be normalized first in implementation. std::vector<Rect> TextRangeRect(const TextRange& text_range) override; - Point TextSinglePoint(Index position, bool trailing) override; + Rect TextSinglePoint(Index position, bool trailing) override; TextHitTestResult HitTest(const Point& point) override; private: - std::u16string text_; + bool edit_mode_ = false; + String text_; std::shared_ptr<DWriteFont> font_; float max_width_ = std::numeric_limits<float>::max(); float max_height_ = std::numeric_limits<float>::max(); diff --git a/include/cru/win/graphics/direct/WindowRenderTarget.hpp b/include/cru/win/graphics/direct/WindowRenderTarget.hpp index 75b1bf20..c197841d 100644 --- a/include/cru/win/graphics/direct/WindowRenderTarget.hpp +++ b/include/cru/win/graphics/direct/WindowRenderTarget.hpp @@ -5,7 +5,7 @@ namespace cru::platform::graphics::win::direct { // Represents a window render target. class D2DWindowRenderTarget : public Object { public: - D2DWindowRenderTarget(gsl::not_null<DirectGraphFactory*> factory, HWND hwnd); + D2DWindowRenderTarget(gsl::not_null<DirectGraphicsFactory*> factory, HWND hwnd); CRU_DELETE_COPY(D2DWindowRenderTarget) CRU_DELETE_MOVE(D2DWindowRenderTarget) @@ -13,7 +13,7 @@ class D2DWindowRenderTarget : public Object { ~D2DWindowRenderTarget() override = default; public: - graphics::win::direct::DirectGraphFactory* GetDirectFactory() const { + graphics::win::direct::DirectGraphicsFactory* GetDirectFactory() const { return factory_; } @@ -33,7 +33,7 @@ class D2DWindowRenderTarget : public Object { void CreateTargetBitmap(); private: - DirectGraphFactory* factory_; + DirectGraphicsFactory* factory_; HWND hwnd_; Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context_; Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_; diff --git a/include/cru/win/gui/GodWindow.hpp b/include/cru/win/gui/GodWindow.hpp index 0343b159..d9a128e6 100644 --- a/include/cru/win/gui/GodWindow.hpp +++ b/include/cru/win/gui/GodWindow.hpp @@ -3,6 +3,7 @@ #include "WindowNativeMessageEventArgs.hpp" #include "cru/common/Event.hpp" +#include "cru/common/String.hpp" #include <memory> diff --git a/include/cru/win/gui/InputMethod.hpp b/include/cru/win/gui/InputMethod.hpp index 51a007d8..3784dcda 100644 --- a/include/cru/win/gui/InputMethod.hpp +++ b/include/cru/win/gui/InputMethod.hpp @@ -65,12 +65,12 @@ class WinInputMethodContext : public WinNativeResource, IEvent<std::nullptr_t>* CompositionEvent() override; - IEvent<std::u16string_view>* TextEvent() override; + IEvent<StringView>* TextEvent() override; private: void OnWindowNativeMessage(WindowNativeMessageEventArgs& args); - std::u16string GetResultString(); + String GetResultString(); AutoHIMC GetHIMC(); @@ -82,6 +82,6 @@ class WinInputMethodContext : public WinNativeResource, Event<std::nullptr_t> composition_start_event_; Event<std::nullptr_t> composition_end_event_; Event<std::nullptr_t> composition_event_; - Event<std::u16string_view> text_event_; + Event<StringView> text_event_; }; } // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/UiApplication.hpp b/include/cru/win/gui/UiApplication.hpp index 4cf46858..4b972fee 100644 --- a/include/cru/win/gui/UiApplication.hpp +++ b/include/cru/win/gui/UiApplication.hpp @@ -7,7 +7,7 @@ #include <memory> namespace cru::platform::graphics::win::direct { -class DirectGraphFactory; +class DirectGraphicsFactory; } namespace cru::platform::gui::win { @@ -33,6 +33,13 @@ class WinUiApplication : public WinNativeResource, void AddOnQuitHandler(std::function<void()> handler) override; + bool IsQuitOnAllWindowClosed() override { + return is_quit_on_all_window_closed_; + } + void SetQuitOnAllWindowClosed(bool quit_on_all_window_closed) override { + is_quit_on_all_window_closed_ = quit_on_all_window_closed; + } + long long SetImmediate(std::function<void()> action) override; long long SetTimeout(std::chrono::milliseconds milliseconds, std::function<void()> action) override; @@ -41,16 +48,19 @@ class WinUiApplication : public WinNativeResource, void CancelTimer(long long id) override; std::vector<INativeWindow*> GetAllWindow() override; - INativeWindow* CreateWindow(INativeWindow* parent, CreateWindowFlag flag) override; + INativeWindow* CreateWindow() override; - cru::platform::graphics::IGraphFactory* GetGraphFactory() override; + cru::platform::graphics::IGraphicsFactory* GetGraphicsFactory() override; - cru::platform::graphics::win::direct::DirectGraphFactory* GetDirectFactory() { + cru::platform::graphics::win::direct::DirectGraphicsFactory* + GetDirectFactory() { return graph_factory_.get(); } ICursorManager* GetCursorManager() override; + IClipboard* GetClipboard() override; + HINSTANCE GetInstanceHandle() const { return instance_handle_; } GodWindow* GetGodWindow() const { return god_window_.get(); } @@ -60,7 +70,9 @@ class WinUiApplication : public WinNativeResource, private: HINSTANCE instance_handle_; - std::unique_ptr<cru::platform::graphics::win::direct::DirectGraphFactory> + bool is_quit_on_all_window_closed_ = true; + + std::unique_ptr<cru::platform::graphics::win::direct::DirectGraphicsFactory> graph_factory_; std::unique_ptr<GodWindow> god_window_; diff --git a/include/cru/win/gui/Window.hpp b/include/cru/win/gui/Window.hpp index 97a74fa7..41eac5fa 100644 --- a/include/cru/win/gui/Window.hpp +++ b/include/cru/win/gui/Window.hpp @@ -2,7 +2,6 @@ #include "Resource.hpp" #include "WindowNativeMessageEventArgs.hpp" -#include "cru/platform/GraphBase.hpp" #include "cru/platform/gui/Base.hpp" #include "cru/platform/gui/Window.hpp" #include "cru/win/graphics/direct/WindowRenderTarget.hpp" @@ -14,8 +13,7 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::WinNativeWindow") public: - WinNativeWindow(WinUiApplication* application, WindowClass* window_class, - DWORD window_style, WinNativeWindow* parent); + explicit WinNativeWindow(WinUiApplication* application); CRU_DELETE_COPY(WinNativeWindow) CRU_DELETE_MOVE(WinNativeWindow) @@ -26,13 +24,20 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { void Close() override; WinNativeWindow* GetParent() override { return parent_window_; } + void SetParent(INativeWindow* parent) override; - bool IsVisible() override; - void SetVisible(bool is_visible) override; + WindowStyleFlag GetStyleFlag() override { return style_flag_; } + void SetStyleFlag(WindowStyleFlag flag) override; + + WindowVisibilityType GetVisibility() override { return visibility_; } + void SetVisibility(WindowVisibilityType visibility) override; Size GetClientSize() override; void SetClientSize(const Size& size) override; + Rect GetClientRect() override; + void SetClientRect(const Rect& rect) override; + // Get the rect of the window containing frame. // The lefttop of the rect is relative to screen lefttop. Rect GetWindowRect() override; @@ -41,6 +46,8 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { // The lefttop of the rect is relative to screen lefttop. void SetWindowRect(const Rect& rect) override; + bool RequestFocus() override; + Point GetMousePosition() override; bool CaptureMouse() override; @@ -51,8 +58,12 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { void SetCursor(std::shared_ptr<ICursor> cursor) override; + IEvent<std::nullptr_t>* CreateEvent() override { return &create_event_; } IEvent<std::nullptr_t>* DestroyEvent() override { return &destroy_event_; } IEvent<std::nullptr_t>* PaintEvent() override { return &paint_event_; } + IEvent<WindowVisibilityType>* VisibilityChangeEvent() override { + return &visibility_change_event_; + } IEvent<Size>* ResizeEvent() override { return &resize_event_; } IEvent<FocusChangeType>* FocusEvent() override { return &focus_event_; } IEvent<MouseEnterLeaveType>* MouseEnterLeaveEvent() override { @@ -106,6 +117,15 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { return result; } + inline RECT DipToPixel(const Rect& dip_rect) { + RECT result; + result.left = DipToPixel(dip_rect.left); + result.top = DipToPixel(dip_rect.top); + result.right = DipToPixel(dip_rect.GetRight()); + result.bottom = DipToPixel(dip_rect.GetBottom()); + return result; + } + inline float PixelToDip(const int pixel) { return static_cast<float>(pixel) * 96.0f / GetDpi(); } @@ -114,14 +134,24 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { return Point(PixelToDip(pi_point.x), PixelToDip(pi_point.y)); } + inline Rect PixelToDip(const RECT& pi_rect) { + return Rect::FromVertices(PixelToDip(pi_rect.left), PixelToDip(pi_rect.top), + PixelToDip(pi_rect.right), + PixelToDip(pi_rect.bottom)); + } + private: // Get the client rect in pixel. RECT GetClientRectPixel(); + void RecreateWindow(); + //*************** region: native messages *************** + void OnCreateInternal(); void OnDestroyInternal(); void OnPaintInternal(); + void OnMoveInternal(int new_left, int new_top); void OnResizeInternal(int new_width, int new_height); void OnSetFocusInternal(); @@ -142,15 +172,12 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { private: WinUiApplication* application_; - // when delete is called first, it set this to true to indicate - // destroy message handler not to double delete this instance; - // when destroy handler is called first (by user action or method - // Close), it set this to true to indicate delete not call Close - // again. - bool sync_flag_ = false; + WindowStyleFlag style_flag_{}; + WindowVisibilityType visibility_ = WindowVisibilityType::Hide; + Rect client_rect_{100, 100, 400, 300}; - HWND hwnd_; - WinNativeWindow* parent_window_; + HWND hwnd_ = nullptr; + WinNativeWindow* parent_window_ = nullptr; float dpi_; @@ -164,9 +191,11 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { std::unique_ptr<WinInputMethodContext> input_method_context_; + Event<std::nullptr_t> create_event_; Event<std::nullptr_t> destroy_event_; Event<std::nullptr_t> paint_event_; Event<Size> resize_event_; + Event<WindowVisibilityType> visibility_change_event_; Event<FocusChangeType> focus_event_; Event<MouseEnterLeaveType> mouse_enter_leave_event_; Event<Point> mouse_move_event_; diff --git a/include/cru/xml/Base.hpp b/include/cru/xml/Base.hpp new file mode 100644 index 00000000..5d6fe144 --- /dev/null +++ b/include/cru/xml/Base.hpp @@ -0,0 +1,11 @@ +#pragma once + +#ifdef CRU_PLATFORM_WINDOWS +#ifdef CRU_XML_EXPORT_API +#define CRU_XML_API __declspec(dllexport) +#else +#define CRU_XML_API __declspec(dllimport) +#endif +#else +#define CRU_XML_API +#endif diff --git a/include/cru/xml/XmlNode.hpp b/include/cru/xml/XmlNode.hpp index cf2543c9..38f09d14 100644 --- a/include/cru/xml/XmlNode.hpp +++ b/include/cru/xml/XmlNode.hpp @@ -1,5 +1,7 @@ #pragma once +#include "Base.hpp" + #include "cru/common/String.hpp" #include <algorithm> @@ -10,7 +12,7 @@ namespace cru::xml { class XmlElementNode; class XmlTextNode; -class XmlNode { +class CRU_XML_API XmlNode { friend XmlElementNode; public: @@ -40,7 +42,7 @@ class XmlNode { XmlElementNode* parent_ = nullptr; }; -class XmlTextNode : public XmlNode { +class CRU_XML_API XmlTextNode : public XmlNode { public: XmlTextNode() : XmlNode(Type::Text) {} explicit XmlTextNode(String text) @@ -61,7 +63,7 @@ class XmlTextNode : public XmlNode { String text_; }; -class XmlElementNode : public XmlNode { +class CRU_XML_API XmlElementNode : public XmlNode { public: XmlElementNode() : XmlNode(Type::Element) {} explicit XmlElementNode(String tag, @@ -86,9 +88,9 @@ class XmlElementNode : public XmlNode { } const std::vector<XmlNode*> GetChildren() const { return children_; } - int GetChildCount() const { return children_.size(); } + Index GetChildCount() const { return children_.size(); } String GetAttribute(const String& key) const { return attributes_.at(key); } - XmlNode* GetChildAt(int index) const { return children_[index]; } + XmlNode* GetChildAt(Index index) const { return children_[index]; } void AddAttribute(String key, String value); void AddChild(XmlNode* child); diff --git a/include/cru/xml/XmlParser.hpp b/include/cru/xml/XmlParser.hpp index 188a08f2..e916cc53 100644 --- a/include/cru/xml/XmlParser.hpp +++ b/include/cru/xml/XmlParser.hpp @@ -8,12 +8,12 @@ #include <optional> namespace cru::xml { -class XmlParsingException : public Exception { +class CRU_XML_API XmlParsingException : public Exception { public: using Exception::Exception; }; -class XmlParser { +class CRU_XML_API XmlParser { public: explicit XmlParser(String xml); diff --git a/src/common/String.cpp b/src/common/String.cpp index 1c2ff022..21f3f235 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -39,13 +39,20 @@ String::String(const_pointer str, Index size) { this->capacity_ = size; } +String::String(size_type size, value_type ch) : String() { + reserve(size); + for (Index i = 0; i < size; i++) { + append(ch); + } +} + String::String(std::initializer_list<char16_t> l) : String(l.begin(), l.size()) {} #ifdef CRU_PLATFORM_WINDOWS String::String(const wchar_t* str) : String(str, GetStrSize(str)) {} String::String(const wchar_t* str, Index size) - : String(reinterpret_cast<const std::uint16_t*>(str), size) {} + : String(reinterpret_cast<const char16_t*>(str), size) {} #endif String::String(const String& other) { @@ -426,7 +433,7 @@ std::vector<FormatToken> ParseToFormatTokenList(const String& str) { void FormatAppendFromFormatTokenList( String& current, const std::vector<FormatToken>& format_token_list, Index index) { - for (Index i = index; i < format_token_list.size(); i++) { + for (Index i = index; i < static_cast<Index>(format_token_list.size()); i++) { const auto& token = format_token_list[i]; if (token.type == FormatTokenType::PlaceHolder) { current += u"{}"; diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp index 440db8c4..6e478033 100644 --- a/src/common/StringUtil.cpp +++ b/src/common/StringUtil.cpp @@ -113,6 +113,8 @@ CodePoint Utf16NextCodePoint(const char16_t* ptr, Index size, Index current, CodePoint Utf16PreviousCodePoint(const char16_t* ptr, Index size, Index current, Index* previous_position) { + CRU_UNUSED(size) + CodePoint result; if (current <= 0) { result = k_invalid_code_point; diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp index 798e1256..9750d6a5 100644 --- a/src/osx/graphics/quartz/Painter.cpp +++ b/src/osx/graphics/quartz/Painter.cpp @@ -109,7 +109,7 @@ void QuartzCGContextPainter::StrokeEllipse(const Rect& outline_rect, } void QuartzCGContextPainter::FillEllipse(const Rect& outline_rect, - IBrush* brush, float width) { + IBrush* brush) { Validate(); QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); diff --git a/src/parse/CMakeLists.txt b/src/parse/CMakeLists.txt index 72bac707..17b26a3a 100644 --- a/src/parse/CMakeLists.txt +++ b/src/parse/CMakeLists.txt @@ -13,4 +13,5 @@ add_library(cru_parse SHARED Token.cpp TokenType.cpp ) +target_compile_definitions(cru_parse PRIVATE CRU_PARSE_EXPORT_API) target_link_libraries(cru_parse PUBLIC cru_base) diff --git a/src/parse/RecursiveDescentAlgorithm.cpp b/src/parse/RecursiveDescentAlgorithm.cpp index a6549f8a..8ff2571d 100644 --- a/src/parse/RecursiveDescentAlgorithm.cpp +++ b/src/parse/RecursiveDescentAlgorithm.cpp @@ -4,6 +4,7 @@ namespace cru::parse { bool RecursiveDescentAlgorithm::CanHandle(Grammar *grammar) const { + CRU_UNUSED(grammar); return true; } diff --git a/src/parse/RecursiveDescentAlgorithmContext.cpp b/src/parse/RecursiveDescentAlgorithmContext.cpp index 8de0abc4..acfd9eee 100644 --- a/src/parse/RecursiveDescentAlgorithmContext.cpp +++ b/src/parse/RecursiveDescentAlgorithmContext.cpp @@ -10,6 +10,7 @@ RecursiveDescentAlgorithmContext::~RecursiveDescentAlgorithmContext() = default; ParsingTreeNode* RecursiveDescentAlgorithmContext::Parse( const std::vector<Terminal*>& input) { + CRU_UNUSED(input) // TODO: Implement this. return nullptr; } diff --git a/src/platform/graphics/CMakeLists.txt b/src/platform/graphics/CMakeLists.txt index 7d86db40..692f8e70 100644 --- a/src/platform/graphics/CMakeLists.txt +++ b/src/platform/graphics/CMakeLists.txt @@ -1,5 +1,6 @@ set(CRU_PLATFORM_GRAPHICS_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/platform/graphics) add_library(cru_platform_graphics SHARED + ForDllExport.cpp NullPainter.cpp ) target_sources(cru_platform_graphics PUBLIC @@ -14,4 +15,5 @@ target_sources(cru_platform_graphics PUBLIC ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/TextLayout.hpp ${CRU_PLATFORM_GRAPHICS_INCLUDE_DIR}/util/Painter.hpp ) +target_compile_definitions(cru_platform_graphics PRIVATE CRU_PLATFORM_GRAPHICS_EXPORT_API) target_link_libraries(cru_platform_graphics PUBLIC cru_platform_base) diff --git a/src/platform/graphics/ForDllExport.cpp b/src/platform/graphics/ForDllExport.cpp new file mode 100644 index 00000000..1a571365 --- /dev/null +++ b/src/platform/graphics/ForDllExport.cpp @@ -0,0 +1,7 @@ +#include "cru/platform/graphics/Brush.hpp" +#include "cru/platform/graphics/Factory.hpp" +#include "cru/platform/graphics/Font.hpp" +#include "cru/platform/graphics/Geometry.hpp" +#include "cru/platform/graphics/Painter.hpp" +#include "cru/platform/graphics/Resource.hpp" +#include "cru/platform/graphics/TextLayout.hpp" diff --git a/src/toml/CMakeLists.txt b/src/toml/CMakeLists.txt index 0285b454..be04ad79 100644 --- a/src/toml/CMakeLists.txt +++ b/src/toml/CMakeLists.txt @@ -2,4 +2,5 @@ add_library(cru_toml SHARED TomlDocument.cpp TomlParser.cpp ) +target_compile_definitions(cru_toml PRIVATE CRU_TOML_EXPORT_API) target_link_libraries(cru_toml PUBLIC cru_base) diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp index 681b44b7..05324865 100644 --- a/src/ui/components/Menu.cpp +++ b/src/ui/components/Menu.cpp @@ -92,7 +92,7 @@ PopupMenu::PopupMenu(controls::Control* attached_control) menu_ = new Menu(); - menu_->SetOnItemClick([this](Index _) { this->Close(); }); + menu_->SetOnItemClick([this](Index) { this->Close(); }); popup_->AddChild(menu_->GetRootControl(), 0); } diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index 61e6aef6..0f136034 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -1,6 +1,7 @@ #include "cru/ui/controls/TextHostControlService.hpp" #include "../Helper.hpp" +#include "cru/common/Base.hpp" #include "cru/common/Logger.hpp" #include "cru/common/String.hpp" #include "cru/common/StringUtil.hpp" @@ -28,6 +29,7 @@ TextControlMovePattern TextControlMovePattern::kLeft( u"Left", helper::ShortcutKeyBind(platform::gui::KeyCode::Left), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) Utf16PreviousCodePoint(text, current_position, ¤t_position); return current_position; }); @@ -35,6 +37,7 @@ TextControlMovePattern TextControlMovePattern::kRight( u"Right", helper::ShortcutKeyBind(platform::gui::KeyCode::Right), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) Utf16NextCodePoint(text, current_position, ¤t_position); return current_position; }); @@ -44,6 +47,7 @@ TextControlMovePattern TextControlMovePattern::kCtrlLeft( platform::gui::KeyModifiers::ctrl), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) return Utf16PreviousWord(text, current_position); }); TextControlMovePattern TextControlMovePattern::kCtrlRight( @@ -52,12 +56,14 @@ TextControlMovePattern TextControlMovePattern::kCtrlRight( platform::gui::KeyModifiers::ctrl), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) return Utf16NextWord(text, current_position); }); TextControlMovePattern TextControlMovePattern::kUp( u"Up", helper::ShortcutKeyBind(platform::gui::KeyCode::Up), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(text) auto text_render_object = service->GetTextRenderObject(); auto rect = text_render_object->TextSinglePoint(current_position, false); rect.top -= 0.1f; @@ -68,6 +74,7 @@ TextControlMovePattern TextControlMovePattern::kDown( u"Down", helper::ShortcutKeyBind(platform::gui::KeyCode::Down), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(text) auto text_render_object = service->GetTextRenderObject(); auto rect = text_render_object->TextSinglePoint(current_position, false); rect.top += rect.height + 0.1f; @@ -78,32 +85,46 @@ TextControlMovePattern TextControlMovePattern::kHome( u"Home(Line Begin)", helper::ShortcutKeyBind(platform::gui::KeyCode::Home), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) return Utf16BackwardUntil(text, current_position, - [](char16_t c) { return c == u'\n'; }); + [](CodePoint c) { return c == u'\n'; }); }); TextControlMovePattern TextControlMovePattern::kEnd( u"End(Line End)", helper::ShortcutKeyBind(platform::gui::KeyCode::End), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) return Utf16ForwardUntil(text, current_position, - [](char16_t c) { return c == u'\n'; }); + [](CodePoint c) { return c == u'\n'; }); }); TextControlMovePattern TextControlMovePattern::kCtrlHome( u"Ctrl+Home(Document Begin)", helper::ShortcutKeyBind(platform::gui::KeyCode::Home, platform::gui::KeyModifiers::ctrl), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return 0; }); + gsl::index current_position) { + CRU_UNUSED(service) + CRU_UNUSED(text) + CRU_UNUSED(current_position) + return 0; + }); TextControlMovePattern TextControlMovePattern::kCtrlEnd( u"Ctrl+End(Document End)", helper::ShortcutKeyBind(platform::gui::KeyCode::End, platform::gui::KeyModifiers::ctrl), [](TextHostControlService* service, StringView text, - gsl::index current_position) { return text.size(); }); + gsl::index current_position) { + CRU_UNUSED(service) + CRU_UNUSED(text) + CRU_UNUSED(current_position) + return text.size(); + }); TextControlMovePattern TextControlMovePattern::kPageUp( u"PageUp", helper::ShortcutKeyBind(platform::gui::KeyCode::PageUp), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) + CRU_UNUSED(text) // TODO: Implement this. return current_position; }); @@ -111,6 +132,8 @@ TextControlMovePattern TextControlMovePattern::kPageDown( u"PageDown", helper::ShortcutKeyBind(platform::gui::KeyCode::PageDown), [](TextHostControlService* service, StringView text, gsl::index current_position) { + CRU_UNUSED(service) + CRU_UNUSED(text) // TODO: Implement this. return current_position; }); diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index 0e65da92..f7665beb 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -147,7 +147,6 @@ Rect TextRenderObject::GetCaretRectInContent() { const auto caret_top_center = this->text_layout_->TextSinglePoint(caret_pos, false); - const auto font_height = this->font_->GetFontSize(); const auto caret_width = this->caret_width_; auto rect = Rect{caret_top_center.left - caret_width / 2.0f, diff --git a/src/win/DebugLogger.hpp b/src/win/DebugLogger.hpp index 598ee9e8..5e78af22 100644 --- a/src/win/DebugLogger.hpp +++ b/src/win/DebugLogger.hpp @@ -13,10 +13,11 @@ class WinDebugLoggerSource : public ::cru::log::ILogSource { ~WinDebugLoggerSource() = default; - void Write(::cru::log::LogLevel level, const std::u16string& s) override { + void Write(::cru::log::LogLevel level, StringView s) override { CRU_UNUSED(level) - ::OutputDebugStringW(reinterpret_cast<const wchar_t*>(s.c_str())); + String m = s.ToString(); + ::OutputDebugStringW(reinterpret_cast<const wchar_t*>(m.c_str())); } }; } // namespace cru::platform::win diff --git a/src/win/Exception.cpp b/src/win/Exception.cpp index df2103fd..2664b092 100644 --- a/src/win/Exception.cpp +++ b/src/win/Exception.cpp @@ -1,6 +1,5 @@ #include "cru/win/Exception.hpp" -#include <fmt/format.h> #include <optional> namespace cru::platform::win { @@ -8,10 +7,9 @@ namespace cru::platform::win { inline String HResultMakeMessage(HRESULT h_result, std::optional<String> message) { if (message.has_value()) - return fmt::format(FMT_STRING(L"HRESULT: {:#08x}. Message: {}"), h_result, - message->WinCStr()); + return Format(u"HRESULT: {}. Message: {}", h_result, message->WinCStr()); else - return fmt::format(FMT_STRING(L"HRESULT: {:#08x}."), h_result); + return Format(u"HRESULT: {}.", h_result); } HResultError::HResultError(HRESULT h_result) @@ -26,8 +24,8 @@ HResultError::HResultError(HRESULT h_result, h_result_(h_result) {} inline String Win32MakeMessage(DWORD error_code, String message) { - return fmt::format(L"Last error code: {:#04x}.\nMessage: {}\n", error_code, - message.WinCStr()); + return Format(u"Last error code: {}.\nMessage: {}\n", error_code, + message.WinCStr()); } Win32Error::Win32Error(std::string_view message) diff --git a/src/win/HeapDebug.cpp b/src/win/HeapDebug.cpp index 6ec1ffcc..b1b9fe1a 100644 --- a/src/win/HeapDebug.cpp +++ b/src/win/HeapDebug.cpp @@ -1,11 +1,9 @@ #include "cru/win/WinPreConfig.hpp" -#include "cru/platform/HeapDebug.hpp" - #include <crtdbg.h> namespace cru::platform { void SetupHeapDebug() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); } -} +} // namespace cru::platform diff --git a/src/win/StdOutLogger.hpp b/src/win/StdOutLogger.hpp index bff8b30e..b3a22dd5 100644 --- a/src/win/StdOutLogger.hpp +++ b/src/win/StdOutLogger.hpp @@ -15,10 +15,11 @@ class WinStdOutLoggerSource : public ::cru::log::ILogSource { ~WinStdOutLoggerSource() = default; - void Write(::cru::log::LogLevel level, const std::u16string& s) override { + void Write(::cru::log::LogLevel level, StringView s) override { CRU_UNUSED(level) - std::fputws(reinterpret_cast<const wchar_t*>(s.c_str()), stdout); + String m = s.ToString(); + std::fputws(reinterpret_cast<const wchar_t*>(m.c_str()), stdout); } }; } // namespace cru::platform::win diff --git a/src/win/graphics/direct/Brush.cpp b/src/win/graphics/direct/Brush.cpp index b7842b97..eb6ea973 100644 --- a/src/win/graphics/direct/Brush.cpp +++ b/src/win/graphics/direct/Brush.cpp @@ -5,8 +5,8 @@ #include "cru/win/graphics/direct/Factory.hpp" namespace cru::platform::graphics::win::direct { -D2DSolidColorBrush::D2DSolidColorBrush(DirectGraphFactory* factory) - : DirectGraphResource(factory) { +D2DSolidColorBrush::D2DSolidColorBrush(DirectGraphicsFactory* factory) + : DirectGraphicsResource(factory) { ThrowIfFailed(factory->GetDefaultD2D1DeviceContext()->CreateSolidColorBrush( Convert(color_), &brush_)); } diff --git a/src/win/graphics/direct/Factory.cpp b/src/win/graphics/direct/Factory.cpp index 6694801f..4c4f1a9a 100644 --- a/src/win/graphics/direct/Factory.cpp +++ b/src/win/graphics/direct/Factory.cpp @@ -27,7 +27,7 @@ void InitializeCom() { void UninitializeCom() { ::CoUninitialize(); } } // namespace -DirectGraphFactory::DirectGraphFactory() { +DirectGraphicsFactory::DirectGraphicsFactory() { // TODO! Detect repeated creation. Because I don't think we can create two d2d // and dwrite factory so we need to prevent the "probably dangerous" behavior. @@ -76,31 +76,33 @@ DirectGraphFactory::DirectGraphFactory() { &dwrite_system_font_collection_)); } -DirectGraphFactory::~DirectGraphFactory() { UninitializeCom(); } +DirectGraphicsFactory::~DirectGraphicsFactory() { UninitializeCom(); } Microsoft::WRL::ComPtr<ID2D1DeviceContext> -DirectGraphFactory::CreateD2D1DeviceContext() { +DirectGraphicsFactory::CreateD2D1DeviceContext() { Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context; ThrowIfFailed(d2d1_device_->CreateDeviceContext( D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context)); return d2d1_device_context; } -std::unique_ptr<ISolidColorBrush> DirectGraphFactory::CreateSolidColorBrush() { +std::unique_ptr<ISolidColorBrush> +DirectGraphicsFactory::CreateSolidColorBrush() { return std::make_unique<D2DSolidColorBrush>(this); } -std::unique_ptr<IGeometryBuilder> DirectGraphFactory::CreateGeometryBuilder() { +std::unique_ptr<IGeometryBuilder> +DirectGraphicsFactory::CreateGeometryBuilder() { return std::make_unique<D2DGeometryBuilder>(this); } -std::unique_ptr<IFont> DirectGraphFactory::CreateFont( - std::u16string font_family, float font_size) { +std::unique_ptr<IFont> DirectGraphicsFactory::CreateFont(String font_family, + float font_size) { return std::make_unique<DWriteFont>(this, std::move(font_family), font_size); } -std::unique_ptr<ITextLayout> DirectGraphFactory::CreateTextLayout( - std::shared_ptr<IFont> font, std::u16string text) { +std::unique_ptr<ITextLayout> DirectGraphicsFactory::CreateTextLayout( + std::shared_ptr<IFont> font, String text) { return std::make_unique<DWriteTextLayout>(this, std::move(font), std::move(text)); } diff --git a/src/win/graphics/direct/Font.cpp b/src/win/graphics/direct/Font.cpp index 1d6a5c88..413c998b 100644 --- a/src/win/graphics/direct/Font.cpp +++ b/src/win/graphics/direct/Font.cpp @@ -7,9 +7,9 @@ #include <utility> namespace cru::platform::graphics::win::direct { -DWriteFont::DWriteFont(DirectGraphFactory* factory, std::u16string font_family, +DWriteFont::DWriteFont(DirectGraphicsFactory* factory, String font_family, float font_size) - : DirectGraphResource(factory), font_family_(std::move(font_family)) { + : DirectGraphicsResource(factory), font_family_(std::move(font_family)) { // Get locale std::array<wchar_t, LOCALE_NAME_MAX_LENGTH> buffer; if (!::GetUserDefaultLocaleName(buffer.data(), diff --git a/src/win/graphics/direct/Geometry.cpp b/src/win/graphics/direct/Geometry.cpp index d07a819f..b37dd9f4 100644 --- a/src/win/graphics/direct/Geometry.cpp +++ b/src/win/graphics/direct/Geometry.cpp @@ -5,15 +5,15 @@ #include "cru/win/graphics/direct/Factory.hpp" namespace cru::platform::graphics::win::direct { -D2DGeometryBuilder::D2DGeometryBuilder(DirectGraphFactory* factory) - : DirectGraphResource(factory) { +D2DGeometryBuilder::D2DGeometryBuilder(DirectGraphicsFactory* factory) + : DirectGraphicsResource(factory) { ThrowIfFailed(factory->GetD2D1Factory()->CreatePathGeometry(&geometry_)); ThrowIfFailed(geometry_->Open(&geometry_sink_)); } void D2DGeometryBuilder::CheckValidation() { if (!IsValid()) - throw ReuseException(L"The geometry builder is already disposed."); + throw ReuseException(u"The geometry builder is already disposed."); } void D2DGeometryBuilder::BeginFigure(const Point& point) { @@ -49,9 +49,9 @@ std::unique_ptr<IGeometry> D2DGeometryBuilder::Build() { return geometry; } -D2DGeometry::D2DGeometry(DirectGraphFactory* factory, +D2DGeometry::D2DGeometry(DirectGraphicsFactory* factory, Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry) - : DirectGraphResource(factory), geometry_(std::move(geometry)) {} + : DirectGraphicsResource(factory), geometry_(std::move(geometry)) {} bool D2DGeometry::FillContains(const Point& point) { BOOL result; diff --git a/src/win/graphics/direct/Painter.cpp b/src/win/graphics/direct/Painter.cpp index 26ef92ec..1a43d1d0 100644 --- a/src/win/graphics/direct/Painter.cpp +++ b/src/win/graphics/direct/Painter.cpp @@ -27,6 +27,10 @@ void D2DPainter::SetTransform(const platform::Matrix& matrix) { render_target_->SetTransform(Convert(matrix)); } +void D2DPainter::ConcatTransform(const Matrix& matrix) { + SetTransform(GetTransform() * matrix); +} + void D2DPainter::Clear(const Color& color) { CheckValidation(); render_target_->Clear(Convert(color)); @@ -54,6 +58,24 @@ void D2DPainter::FillRectangle(const Rect& rectangle, IBrush* brush) { render_target_->FillRectangle(Convert(rectangle), b->GetD2DBrushInterface()); } +void D2DPainter::StrokeEllipse(const Rect& outline_rect, IBrush* brush, + float width) { + CheckValidation(); + const auto b = CheckPlatform<ID2DBrush>(brush, GetPlatformId()); + render_target_->DrawEllipse( + D2D1::Ellipse(Convert(outline_rect.GetCenter()), + outline_rect.width / 2.0f, outline_rect.height / 2.0f), + b->GetD2DBrushInterface(), width); +} +void D2DPainter::FillEllipse(const Rect& outline_rect, IBrush* brush) { + CheckValidation(); + const auto b = CheckPlatform<ID2DBrush>(brush, GetPlatformId()); + render_target_->FillEllipse( + D2D1::Ellipse(Convert(outline_rect.GetCenter()), + outline_rect.width / 2.0f, outline_rect.height / 2.0f), + b->GetD2DBrushInterface()); +} + void D2DPainter::StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) { CheckValidation(); @@ -96,6 +118,24 @@ void D2DPainter::PopLayer() { layers_.pop_back(); } +void D2DPainter::PushState() { + Microsoft::WRL::ComPtr<ID2D1Factory> factory = nullptr; + render_target_->GetFactory(&factory); + + Microsoft::WRL::ComPtr<ID2D1DrawingStateBlock> state_block; + factory->CreateDrawingStateBlock(&state_block); + render_target_->SaveDrawingState(state_block.Get()); + + drawing_state_stack_.push_back(std::move(state_block)); +} + +void D2DPainter::PopState() { + Expects(!drawing_state_stack_.empty()); + auto drawing_state = drawing_state_stack_.back(); + drawing_state_stack_.pop_back(); + render_target_->RestoreDrawingState(drawing_state.Get()); +} + void D2DPainter::EndDraw() { if (is_drawing_) { is_drawing_ = false; @@ -106,7 +146,7 @@ void D2DPainter::EndDraw() { void D2DPainter::CheckValidation() { if (!is_drawing_) { throw cru::platform::ReuseException( - L"Can't do that on painter after end drawing."); + u"Can't do that on painter after end drawing."); } } } // namespace cru::platform::graphics::win::direct diff --git a/src/win/graphics/direct/Resource.cpp b/src/win/graphics/direct/Resource.cpp index 6ae74e64..0e9719f4 100644 --- a/src/win/graphics/direct/Resource.cpp +++ b/src/win/graphics/direct/Resource.cpp @@ -5,10 +5,12 @@ namespace cru::platform::graphics::win::direct { String DirectResource::kPlatformId = u"Windows Direct"; -DirectGraphResource::DirectGraphResource(DirectGraphFactory* factory) +DirectGraphicsResource::DirectGraphicsResource(DirectGraphicsFactory* factory) : factory_(factory) { Expects(factory); } -IGraphFactory* DirectGraphResource::GetGraphFactory() { return factory_; } +IGraphicsFactory* DirectGraphicsResource::GetGraphicsFactory() { + return factory_; +} } // namespace cru::platform::graphics::win::direct diff --git a/src/win/graphics/direct/TextLayout.cpp b/src/win/graphics/direct/TextLayout.cpp index 0b3c68ca..bec4a972 100644 --- a/src/win/graphics/direct/TextLayout.cpp +++ b/src/win/graphics/direct/TextLayout.cpp @@ -1,4 +1,5 @@ #include "cru/win/graphics/direct/TextLayout.hpp" +#include <dwrite.h> #include "cru/common/Logger.hpp" #include "cru/platform/Check.hpp" @@ -9,10 +10,9 @@ #include <utility> namespace cru::platform::graphics::win::direct { -DWriteTextLayout::DWriteTextLayout(DirectGraphFactory* factory, - std::shared_ptr<IFont> font, - std::u16string text) - : DirectGraphResource(factory), text_(std::move(text)) { +DWriteTextLayout::DWriteTextLayout(DirectGraphicsFactory* factory, + std::shared_ptr<IFont> font, String text) + : DirectGraphicsResource(factory), text_(std::move(text)) { Expects(font); font_ = CheckPlatform<DWriteFont>(font, GetPlatformId()); @@ -24,12 +24,10 @@ DWriteTextLayout::DWriteTextLayout(DirectGraphFactory* factory, DWriteTextLayout::~DWriteTextLayout() = default; -std::u16string DWriteTextLayout::GetText() { return text_; } +String DWriteTextLayout::GetText() { return text_; } -std::u16string_view DWriteTextLayout::GetTextView() { return text_; } - -void DWriteTextLayout::SetText(std::u16string new_text) { - text_.swap(new_text); +void DWriteTextLayout::SetText(String new_text) { + text_ = std::move(new_text); ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout( reinterpret_cast<const wchar_t*>(text_.c_str()), static_cast<UINT32>(text_.size()), font_->GetComInterface(), max_width_, @@ -58,6 +56,44 @@ void DWriteTextLayout::SetMaxHeight(float max_height) { ThrowIfFailed(text_layout_->SetMaxHeight(max_height_)); } +bool DWriteTextLayout::IsEditMode() { return edit_mode_; } + +void DWriteTextLayout::SetEditMode(bool enable) { + edit_mode_ = enable; + // TODO: Implement this. +} + +Index DWriteTextLayout::GetLineIndexFromCharIndex(Index char_index) { + if (char_index < 0 || char_index >= text_.size()) { + return -1; + } + + auto line_index = 0; + for (Index i = 0; i < char_index; ++i) { + if (text_[i] == u'\n') { + line_index++; + } + } + + return line_index; +} + +float DWriteTextLayout::GetLineHeight(Index line_index) { + Index count = GetLineCount(); + std::vector<DWRITE_LINE_METRICS> line_metrics(count); + + UINT32 actual_line_count = 0; + text_layout_->GetLineMetrics(line_metrics.data(), static_cast<UINT32>(count), + &actual_line_count); + return line_metrics[line_index].height; +} + +Index DWriteTextLayout::GetLineCount() { + UINT32 line_count = 0; + text_layout_->GetLineMetrics(nullptr, 0, &line_count); + return line_count; +} + Rect DWriteTextLayout::GetTextBounds(bool includingTrailingSpace) { DWRITE_TEXT_METRICS metrics; ThrowIfFailed(text_layout_->GetMetrics(&metrics)); @@ -100,14 +136,14 @@ std::vector<Rect> DWriteTextLayout::TextRangeRect( return result; } -Point DWriteTextLayout::TextSinglePoint(Index position, bool trailing) { +Rect DWriteTextLayout::TextSinglePoint(Index position, bool trailing) { DWRITE_HIT_TEST_METRICS metrics; FLOAT left; FLOAT top; ThrowIfFailed(text_layout_->HitTestTextPosition(static_cast<UINT32>(position), static_cast<BOOL>(trailing), &left, &top, &metrics)); - return Point{left, top}; + return Rect{left, top, 0, GetFont()->GetFontSize()}; } TextHitTestResult DWriteTextLayout::HitTest(const Point& point) { @@ -121,7 +157,6 @@ TextHitTestResult DWriteTextLayout::HitTest(const Point& point) { TextHitTestResult result; result.position = metrics.textPosition; result.trailing = trailing != 0; - result.insideText = inside != 0; return result; } } // namespace cru::platform::graphics::win::direct diff --git a/src/win/graphics/direct/WindowRenderTarget.cpp b/src/win/graphics/direct/WindowRenderTarget.cpp index 7479ae24..020ce4b4 100644 --- a/src/win/graphics/direct/WindowRenderTarget.cpp +++ b/src/win/graphics/direct/WindowRenderTarget.cpp @@ -5,7 +5,7 @@ namespace cru::platform::graphics::win::direct { D2DWindowRenderTarget::D2DWindowRenderTarget( - gsl::not_null<DirectGraphFactory*> factory, HWND hwnd) + gsl::not_null<DirectGraphicsFactory*> factory, HWND hwnd) : factory_(factory), hwnd_(hwnd) { const auto d3d11_device = factory->GetD3D11Device(); const auto dxgi_factory = factory->GetDxgiFactory(); diff --git a/src/win/gui/InputMethod.cpp b/src/win/gui/InputMethod.cpp index cc237e88..47e17109 100644 --- a/src/win/gui/InputMethod.cpp +++ b/src/win/gui/InputMethod.cpp @@ -104,19 +104,19 @@ CompositionClauses GetCompositionClauses(HIMC imm_context, int target_start, return result; } -std::u16string GetString(HIMC imm_context) { +String GetString(HIMC imm_context) { LONG string_size = ::ImmGetCompositionString(imm_context, GCS_COMPSTR, NULL, 0); - std::u16string result((string_size / sizeof(char16_t)), 0); + String result((string_size / sizeof(char16_t)), 0); ::ImmGetCompositionString(imm_context, GCS_COMPSTR, result.data(), string_size); return result; } -std::u16string GetResultString(HIMC imm_context) { +String GetResultString(HIMC imm_context) { LONG string_size = ::ImmGetCompositionString(imm_context, GCS_RESULTSTR, NULL, 0); - std::u16string result((string_size / sizeof(char16_t)), 0); + String result((string_size / sizeof(char16_t)), 0); ::ImmGetCompositionString(imm_context, GCS_RESULTSTR, result.data(), string_size); return result; @@ -217,9 +217,7 @@ IEvent<std::nullptr_t>* WinInputMethodContext::CompositionEvent() { return &composition_event_; } -IEvent<std::u16string_view>* WinInputMethodContext::TextEvent() { - return &text_event_; -} +IEvent<StringView>* WinInputMethodContext::TextEvent() { return &text_event_; } void WinInputMethodContext::OnWindowNativeMessage( WindowNativeMessageEventArgs& args) { @@ -275,7 +273,7 @@ void WinInputMethodContext::OnWindowNativeMessage( } } -std::u16string WinInputMethodContext::GetResultString() { +String WinInputMethodContext::GetResultString() { auto himc = GetHIMC(); auto result = win::GetResultString(himc.Get()); return result; diff --git a/src/win/gui/UiApplication.cpp b/src/win/gui/UiApplication.cpp index f4541dd0..cb0f0a4c 100644 --- a/src/win/gui/UiApplication.cpp +++ b/src/win/gui/UiApplication.cpp @@ -37,7 +37,7 @@ WinUiApplication::WinUiApplication() { std::make_unique<::cru::platform::win::WinStdOutLoggerSource>()); graph_factory_ = std::make_unique< - cru::platform::graphics::win::direct::DirectGraphFactory>(); + cru::platform::graphics::win::direct::DirectGraphicsFactory>(); god_window_ = std::make_unique<GodWindow>(this); timer_manager_ = std::make_unique<TimerManager>(god_window_.get()); @@ -99,24 +99,22 @@ std::vector<INativeWindow*> WinUiApplication::GetAllWindow() { return result; } -INativeWindow* WinUiApplication::CreateWindow(INativeWindow* parent, - CreateWindowFlag flag) { - WinNativeWindow* p = nullptr; - if (parent != nullptr) { - p = CheckPlatform<WinNativeWindow>(parent, GetPlatformId()); - } - return new WinNativeWindow(this, window_manager_->GetGeneralWindowClass(), - flag & CreateWindowFlags::NoCaptionAndBorder - ? WS_POPUP - : WS_OVERLAPPEDWINDOW, - p); +INativeWindow* WinUiApplication::CreateWindow() { + return new WinNativeWindow(this); } -cru::platform::graphics::IGraphFactory* WinUiApplication::GetGraphFactory() { +cru::platform::graphics::IGraphicsFactory* +WinUiApplication::GetGraphicsFactory() { return graph_factory_.get(); } ICursorManager* WinUiApplication::GetCursorManager() { return cursor_manager_.get(); } + +IClipboard* WinUiApplication::GetClipboard() { + // TODO: Implement this. + return nullptr; +} + } // namespace cru::platform::gui::win diff --git a/src/win/gui/Window.cpp b/src/win/gui/Window.cpp index 4c75a319..7ee2fb71 100644 --- a/src/win/gui/Window.cpp +++ b/src/win/gui/Window.cpp @@ -3,8 +3,10 @@ #include "WindowManager.hpp" #include "cru/common/Logger.hpp" #include "cru/platform/Check.hpp" +#include "cru/platform/graphics/NullPainter.hpp" #include "cru/platform/gui/Base.hpp" #include "cru/platform/gui/DebugFlags.hpp" +#include "cru/platform/gui/Window.hpp" #include "cru/win/graphics/direct/WindowPainter.hpp" #include "cru/win/gui/Cursor.hpp" #include "cru/win/gui/Exception.hpp" @@ -13,104 +15,165 @@ #include "cru/win/gui/UiApplication.hpp" #include "cru/win/gui/WindowClass.hpp" -#include <imm.h> #include <windowsx.h> +#include <winuser.h> #include <memory> namespace cru::platform::gui::win { -WinNativeWindow::WinNativeWindow(WinUiApplication* application, - WindowClass* window_class, DWORD window_style, - WinNativeWindow* parent) - : application_(application), parent_window_(parent) { - Expects(application); // application can't be null. +namespace { +inline int DipToPixel(const float dip, const float dpi) { + return static_cast<int>(dip * dpi / 96.0f); +} - if (parent != nullptr) { - throw new std::runtime_error("Can't use a invalid window as parent."); - } +inline float PixelToDip(const int pixel, const float dpi) { + return static_cast<float>(pixel) * 96.0f / dpi; +} - const auto window_manager = application->GetWindowManager(); +DWORD CalcWindowStyle(WindowStyleFlag flag) { + return flag & WindowStyleFlags::NoCaptionAndBorder ? WS_POPUP + : WS_OVERLAPPEDWINDOW; +} - hwnd_ = CreateWindowExW( - 0, window_class->GetName(), L"", window_style, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - parent == nullptr ? nullptr : parent->GetWindowHandle(), nullptr, - application->GetInstanceHandle(), nullptr); +Rect CalcWindowRectFromClient(const Rect& rect, WindowStyleFlag style_flag, + float dpi) { + RECT r; + r.left = DipToPixel(rect.left, dpi); + r.top = DipToPixel(rect.top, dpi); + r.right = DipToPixel(rect.GetRight(), dpi); + r.bottom = DipToPixel(rect.GetBottom(), dpi); + if (!AdjustWindowRectEx(&r, CalcWindowStyle(style_flag), FALSE, 0)) + throw Win32Error(::GetLastError(), "Failed to invoke AdjustWindowRectEx."); - if (hwnd_ == nullptr) - throw Win32Error(::GetLastError(), "Failed to create window."); + Rect result = + Rect::FromVertices(PixelToDip(r.left, dpi), PixelToDip(r.top, dpi), + PixelToDip(r.right, dpi), PixelToDip(r.bottom, dpi)); + return result; +} - auto dpi = ::GetDpiForWindow(hwnd_); - if (dpi == 0) - throw Win32Error(::GetLastError(), "Failed to get dpi of window."); - dpi_ = static_cast<float>(dpi); - log::Debug(u"Dpi of window is {}.", dpi_); +Rect CalcClientRectFromWindow(const Rect& rect, WindowStyleFlag style_flag, + float dpi) { + RECT o{100, 100, 500, 500}; + RECT s = o; + if (!AdjustWindowRectEx(&s, CalcWindowStyle(style_flag), FALSE, 0)) + throw Win32Error(::GetLastError(), "Failed to invoke AdjustWindowRectEx."); - window_manager->RegisterWindow(hwnd_, this); + Rect result = rect; + result.Shrink(Thickness(PixelToDip(s.left - o.left, dpi), + PixelToDip(o.top - s.top, dpi), + PixelToDip(s.right - o.right, dpi), + PixelToDip(s.bottom - o.bottom, dpi))); - SetCursor(application->GetCursorManager()->GetSystemCursor( - cru::platform::gui::SystemCursorType::Arrow)); + return result; +} +} // namespace - window_render_target_ = - std::make_unique<graphics::win::direct::D2DWindowRenderTarget>( - application->GetDirectFactory(), hwnd_); - window_render_target_->SetDpi(dpi_, dpi_); +WinNativeWindow::WinNativeWindow(WinUiApplication* application) + : application_(application) { + Expects(application); // application can't be null. +} - input_method_context_ = std::make_unique<WinInputMethodContext>(this); - input_method_context_->DisableIME(); +WinNativeWindow::~WinNativeWindow() { Close(); } + +void WinNativeWindow::Close() { + if (hwnd_) ::DestroyWindow(hwnd_); } -WinNativeWindow::~WinNativeWindow() { - if (!sync_flag_) { - sync_flag_ = true; - Close(); +void WinNativeWindow::SetParent(INativeWindow* parent) { + auto p = CheckPlatform<WinNativeWindow>(parent, GetPlatformId()); + parent_window_ = p; + + if (hwnd_) { + ::SetParent(hwnd_, parent_window_->hwnd_); } } -void WinNativeWindow::Close() { ::DestroyWindow(hwnd_); } +void WinNativeWindow::SetStyleFlag(WindowStyleFlag flag) { + if (flag == style_flag_) return; -bool WinNativeWindow::IsVisible() { return ::IsWindowVisible(hwnd_); } - -void WinNativeWindow::SetVisible(bool is_visible) { - is_visible ? ShowWindow(hwnd_, SW_SHOWNORMAL) : ShowWindow(hwnd_, SW_HIDE); + style_flag_ = flag; + if (hwnd_) { + SetWindowLongPtrW(hwnd_, GWL_STYLE, + static_cast<LONG_PTR>(CalcWindowStyle(style_flag_))); + } } -Size WinNativeWindow::GetClientSize() { - const auto pixel_rect = GetClientRectPixel(); - return Size(PixelToDip(pixel_rect.right), PixelToDip(pixel_rect.bottom)); + +void WinNativeWindow::SetVisibility(WindowVisibilityType visibility) { + if (visibility == visibility_) return; + visibility_ = visibility; + + if (!hwnd_) { + RecreateWindow(); + } + + if (visibility == WindowVisibilityType::Show) { + ShowWindow(hwnd_, SW_SHOWNORMAL); + } else if (visibility == WindowVisibilityType::Hide) { + ShowWindow(hwnd_, SW_HIDE); + } else if (visibility == WindowVisibilityType::Minimize) { + ShowWindow(hwnd_, SW_MINIMIZE); + } } +Size WinNativeWindow::GetClientSize() { return GetClientRect().GetSize(); } + void WinNativeWindow::SetClientSize(const Size& size) { - const auto window_style = - static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_STYLE)); - const auto window_ex_style = - static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_EXSTYLE)); + client_rect_.SetSize(size); - RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = DipToPixel(size.width); - rect.bottom = DipToPixel(size.height); - if (!AdjustWindowRectEx(&rect, window_style, FALSE, window_ex_style)) - throw Win32Error(::GetLastError(), "Failed to invoke AdjustWindowRectEx."); + if (hwnd_) { + RECT rect = + DipToPixel(CalcWindowRectFromClient(client_rect_, style_flag_, dpi_)); - if (!SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE)) - throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); + if (!SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE)) + throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); + } } -Rect WinNativeWindow::GetWindowRect() { - RECT rect; - if (!::GetWindowRect(hwnd_, &rect)) - throw Win32Error(::GetLastError(), "Failed to invoke GetWindowRect."); +Rect WinNativeWindow::GetClientRect() { return client_rect_; } + +void WinNativeWindow::SetClientRect(const Rect& rect) { + client_rect_ = rect; - return Rect::FromVertices(PixelToDip(rect.left), PixelToDip(rect.top), - PixelToDip(rect.right), PixelToDip(rect.bottom)); + if (hwnd_) { + RECT r = + DipToPixel(CalcWindowRectFromClient(client_rect_, style_flag_, dpi_)); + + if (!SetWindowPos(hwnd_, nullptr, 0, 0, r.right - r.left, r.bottom - r.top, + SWP_NOZORDER | SWP_NOMOVE)) + throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); + } +} + +Rect WinNativeWindow::GetWindowRect() { + if (hwnd_) { + RECT rect; + if (!::GetWindowRect(hwnd_, &rect)) + throw Win32Error(::GetLastError(), "Failed to invoke GetWindowRect."); + + return Rect::FromVertices(PixelToDip(rect.left), PixelToDip(rect.top), + PixelToDip(rect.right), PixelToDip(rect.bottom)); + } else { + return CalcWindowRectFromClient(client_rect_, style_flag_, dpi_); + } } void WinNativeWindow::SetWindowRect(const Rect& rect) { - if (!SetWindowPos(hwnd_, nullptr, DipToPixel(rect.left), DipToPixel(rect.top), - DipToPixel(rect.GetRight()), DipToPixel(rect.GetBottom()), - SWP_NOZORDER)) - throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); + client_rect_ = CalcClientRectFromWindow(rect, style_flag_, dpi_); + + if (hwnd_) { + if (!SetWindowPos(hwnd_, nullptr, DipToPixel(rect.left), + DipToPixel(rect.top), DipToPixel(rect.GetRight()), + DipToPixel(rect.GetBottom()), SWP_NOZORDER)) + throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); + } +} + +bool WinNativeWindow::RequestFocus() { + if (hwnd_) { + SetFocus(hwnd_); + return true; + } + return false; } Point WinNativeWindow::GetMousePosition() { @@ -143,8 +206,11 @@ void WinNativeWindow::RequestRepaint() { } std::unique_ptr<graphics::IPainter> WinNativeWindow::BeginPaint() { - return std::make_unique<graphics::win::direct::D2DWindowPainter>( - window_render_target_.get()); + if (hwnd_) + return std::make_unique<graphics::win::direct::D2DWindowPainter>( + window_render_target_.get()); + else + return std::make_unique<graphics::NullPainter>(); } void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) { @@ -154,6 +220,8 @@ void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) { cursor_ = CheckPlatform<WinCursor>(cursor, GetPlatformId()); + if (hwnd_) return; + if (!::SetClassLongPtrW(hwnd_, GCLP_HCURSOR, reinterpret_cast<LONG_PTR>(cursor_->GetHandle()))) { log::TagWarn(log_tag, @@ -163,9 +231,9 @@ void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) { return; } - if (!IsVisible()) return; + if (GetVisibility() != WindowVisibilityType::Show) return; - auto lg = [](const std::u16string_view& reason) { + auto lg = [](StringView reason) { log::TagWarn( log_tag, u"Failed to set cursor because {} when window is visible. (We need to " @@ -320,6 +388,14 @@ bool WinNativeWindow::HandleNativeWindowMessage(HWND hwnd, UINT msg, return true; } return false; + case WM_CREATE: + OnCreateInternal(); + *result = 0; + return true; + case WM_MOVE: + OnMoveInternal(LOWORD(l_param), HIWORD(l_param)); + *result = 0; + return true; case WM_SIZE: OnResizeInternal(LOWORD(l_param), HIWORD(l_param)); *result = 0; @@ -361,19 +437,50 @@ bool WinNativeWindow::HandleNativeWindowMessage(HWND hwnd, UINT msg, RECT WinNativeWindow::GetClientRectPixel() { RECT rect; - if (!GetClientRect(hwnd_, &rect)) + if (!::GetClientRect(hwnd_, &rect)) throw Win32Error(::GetLastError(), "Failed to invoke GetClientRect."); return rect; } +void WinNativeWindow::RecreateWindow() { + const auto window_manager = application_->GetWindowManager(); + auto window_class = window_manager->GetGeneralWindowClass(); + + hwnd_ = CreateWindowExW( + 0, window_class->GetName(), L"", CalcWindowStyle(style_flag_), + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + parent_window_ == nullptr ? nullptr : parent_window_->GetWindowHandle(), + nullptr, application_->GetInstanceHandle(), nullptr); + + if (hwnd_ == nullptr) + throw Win32Error(::GetLastError(), "Failed to create window."); + + auto dpi = ::GetDpiForWindow(hwnd_); + if (dpi == 0) + throw Win32Error(::GetLastError(), "Failed to get dpi of window."); + dpi_ = static_cast<float>(dpi); + log::Debug(u"Dpi of window is {}.", dpi_); + + window_manager->RegisterWindow(hwnd_, this); + + SetCursor(application_->GetCursorManager()->GetSystemCursor( + cru::platform::gui::SystemCursorType::Arrow)); + + window_render_target_ = + std::make_unique<graphics::win::direct::D2DWindowRenderTarget>( + application_->GetDirectFactory(), hwnd_); + window_render_target_->SetDpi(dpi_, dpi_); + + input_method_context_ = std::make_unique<WinInputMethodContext>(this); + input_method_context_->DisableIME(); +} + +void WinNativeWindow::OnCreateInternal() { create_event_.Raise(nullptr); } + void WinNativeWindow::OnDestroyInternal() { destroy_event_.Raise(nullptr); application_->GetWindowManager()->UnregisterWindow(hwnd_); hwnd_ = nullptr; - if (!sync_flag_) { - sync_flag_ = true; - delete this; - } } void WinNativeWindow::OnPaintInternal() { @@ -384,8 +491,15 @@ void WinNativeWindow::OnPaintInternal() { } } +void WinNativeWindow::OnMoveInternal(const int new_left, const int new_top) { + client_rect_.left = PixelToDip(new_left); + client_rect_.top = PixelToDip(new_top); +} + void WinNativeWindow::OnResizeInternal(const int new_width, const int new_height) { + client_rect_.width = PixelToDip(new_width); + client_rect_.height = PixelToDip(new_height); if (!(new_width == 0 && new_height == 0)) { window_render_target_->ResizeBuffer(new_width, new_height); resize_event_.Raise(Size{PixelToDip(new_width), PixelToDip(new_height)}); @@ -399,7 +513,7 @@ void WinNativeWindow::OnSetFocusInternal() { void WinNativeWindow::OnKillFocusInternal() { has_focus_ = false; - focus_event_.Raise(FocusChangeType::Lost); + focus_event_.Raise(FocusChangeType::Lose); } void WinNativeWindow::OnMouseMoveInternal(const POINT point) { diff --git a/src/win/gui/WindowManager.cpp b/src/win/gui/WindowManager.cpp index 4e84e967..31b868b9 100644 --- a/src/win/gui/WindowManager.cpp +++ b/src/win/gui/WindowManager.cpp @@ -37,7 +37,8 @@ void WindowManager::UnregisterWindow(HWND hwnd) { const auto find_result = window_map_.find(hwnd); Expects(find_result != window_map_.end()); // The hwnd is not in the map. window_map_.erase(find_result); - if (window_map_.empty()) application_->RequestQuit(0); + if (window_map_.empty() && application_->IsQuitOnAllWindowClosed()) + application_->RequestQuit(0); } WinNativeWindow* WindowManager::FromHandle(HWND hwnd) { diff --git a/src/xml/CMakeLists.txt b/src/xml/CMakeLists.txt index 20e889ec..014e820c 100644 --- a/src/xml/CMakeLists.txt +++ b/src/xml/CMakeLists.txt @@ -2,4 +2,5 @@ add_library(cru_xml SHARED XmlNode.cpp XmlParser.cpp ) +target_compile_definitions(cru_xml PRIVATE CRU_XML_EXPORT_API) target_link_libraries(cru_xml PUBLIC cru_base) |