From 06d1d0442276a05b6caad6e3468f4afb1e8ee5df Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 28 Jun 2020 00:03:11 +0800 Subject: ... --- include/cru/common/Base.hpp | 47 +++++ include/cru/common/Bitmask.hpp | 42 +++++ include/cru/common/Event.hpp | 213 +++++++++++++++++++++ include/cru/common/Logger.hpp | 92 +++++++++ include/cru/common/base.hpp | 47 ----- include/cru/common/bitmask.hpp | 42 ----- include/cru/common/event.hpp | 213 --------------------- include/cru/common/logger.hpp | 92 --------- include/cru/platform/Check.hpp | 40 ++++ include/cru/platform/Exception.hpp | 28 +++ include/cru/platform/Matrix.hpp | 83 ++++++++ include/cru/platform/Resource.hpp | 10 + include/cru/platform/check.hpp | 40 ---- include/cru/platform/exception.hpp | 28 --- include/cru/platform/graph/Base.hpp | 24 +++ include/cru/platform/graph/Brush.hpp | 11 ++ include/cru/platform/graph/Factory.hpp | 25 +++ include/cru/platform/graph/Font.hpp | 8 + include/cru/platform/graph/Geometry.hpp | 20 ++ include/cru/platform/graph/Painter.hpp | 29 +++ include/cru/platform/graph/Resource.hpp | 10 + include/cru/platform/graph/base.hpp | 24 --- include/cru/platform/graph/brush.hpp | 11 -- include/cru/platform/graph/factory.hpp | 25 --- include/cru/platform/graph/font.hpp | 8 - include/cru/platform/graph/geometry.hpp | 20 -- include/cru/platform/graph/painter.hpp | 29 --- include/cru/platform/graph/resource.hpp | 10 - include/cru/platform/graph/util/Painter.hpp | 17 ++ include/cru/platform/graph/util/painter.hpp | 17 -- include/cru/platform/matrix.hpp | 83 -------- include/cru/platform/native/Base.hpp | 52 +++++ include/cru/platform/native/Cursor.hpp | 15 ++ include/cru/platform/native/Keyboard.hpp | 120 ++++++++++++ include/cru/platform/native/Window.hpp | 67 +++++++ include/cru/platform/native/base.hpp | 52 ----- include/cru/platform/native/cursor.hpp | 15 -- include/cru/platform/native/keyboard.hpp | 120 ------------ include/cru/platform/native/window.hpp | 67 ------- include/cru/platform/resource.hpp | 10 - include/cru/ui/Base.hpp | 281 ++++++++++++++++++++++++++++ include/cru/ui/Control.hpp | 152 +++++++++++++++ include/cru/ui/Window.hpp | 40 ++++ include/cru/ui/base.hpp | 281 ---------------------------- include/cru/ui/control.hpp | 152 --------------- include/cru/ui/controls/Base.hpp | 24 +++ include/cru/ui/controls/Button.hpp | 42 +++++ include/cru/ui/controls/Container.hpp | 28 +++ include/cru/ui/controls/base.hpp | 24 --- include/cru/ui/controls/button.hpp | 42 ----- include/cru/ui/controls/container.hpp | 28 --- include/cru/ui/render/Base.hpp | 12 ++ include/cru/ui/render/base.hpp | 12 -- include/cru/ui/window.hpp | 40 ---- include/cru/win/Exception.hpp | 52 +++++ include/cru/win/String.hpp | 107 +++++++++++ include/cru/win/exception.hpp | 52 ----- include/cru/win/graph/direct/Brush.hpp | 39 ++++ include/cru/win/graph/direct/Exception.hpp | 7 + include/cru/win/graph/direct/Factory.hpp | 58 ++++++ include/cru/win/graph/direct/Font.hpp | 32 ++++ include/cru/win/graph/direct/Geometry.hpp | 57 ++++++ include/cru/win/graph/direct/Painter.hpp | 60 ++++++ include/cru/win/graph/direct/Resource.hpp | 49 +++++ include/cru/win/graph/direct/brush.hpp | 39 ---- include/cru/win/graph/direct/exception.hpp | 7 - include/cru/win/graph/direct/factory.hpp | 58 ------ include/cru/win/graph/direct/font.hpp | 32 ---- include/cru/win/graph/direct/geometry.hpp | 57 ------ include/cru/win/graph/direct/painter.hpp | 60 ------ include/cru/win/graph/direct/resource.hpp | 49 ----- include/cru/win/native/Base.hpp | 19 ++ include/cru/win/native/Cursor.hpp | 47 +++++ include/cru/win/native/Exception.hpp | 7 + include/cru/win/native/Keyboard.hpp | 9 + include/cru/win/native/Resource.hpp | 23 +++ include/cru/win/native/Window.hpp | 174 +++++++++++++++++ include/cru/win/native/base.hpp | 19 -- include/cru/win/native/cursor.hpp | 47 ----- include/cru/win/native/exception.hpp | 7 - include/cru/win/native/keyboard.hpp | 9 - include/cru/win/native/resource.hpp | 23 --- include/cru/win/native/window.hpp | 174 ----------------- include/cru/win/string.hpp | 107 ----------- 84 files changed, 2272 insertions(+), 2272 deletions(-) create mode 100644 include/cru/common/Base.hpp create mode 100644 include/cru/common/Bitmask.hpp create mode 100644 include/cru/common/Event.hpp create mode 100644 include/cru/common/Logger.hpp delete mode 100644 include/cru/common/base.hpp delete mode 100644 include/cru/common/bitmask.hpp delete mode 100644 include/cru/common/event.hpp delete mode 100644 include/cru/common/logger.hpp create mode 100644 include/cru/platform/Check.hpp create mode 100644 include/cru/platform/Exception.hpp create mode 100644 include/cru/platform/Matrix.hpp create mode 100644 include/cru/platform/Resource.hpp delete mode 100644 include/cru/platform/check.hpp delete mode 100644 include/cru/platform/exception.hpp create mode 100644 include/cru/platform/graph/Base.hpp create mode 100644 include/cru/platform/graph/Brush.hpp create mode 100644 include/cru/platform/graph/Factory.hpp create mode 100644 include/cru/platform/graph/Font.hpp create mode 100644 include/cru/platform/graph/Geometry.hpp create mode 100644 include/cru/platform/graph/Painter.hpp create mode 100644 include/cru/platform/graph/Resource.hpp delete mode 100644 include/cru/platform/graph/base.hpp delete mode 100644 include/cru/platform/graph/brush.hpp delete mode 100644 include/cru/platform/graph/factory.hpp delete mode 100644 include/cru/platform/graph/font.hpp delete mode 100644 include/cru/platform/graph/geometry.hpp delete mode 100644 include/cru/platform/graph/painter.hpp delete 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.hpp delete mode 100644 include/cru/platform/matrix.hpp create mode 100644 include/cru/platform/native/Base.hpp create mode 100644 include/cru/platform/native/Cursor.hpp create mode 100644 include/cru/platform/native/Keyboard.hpp create mode 100644 include/cru/platform/native/Window.hpp delete mode 100644 include/cru/platform/native/base.hpp delete mode 100644 include/cru/platform/native/cursor.hpp delete mode 100644 include/cru/platform/native/keyboard.hpp delete mode 100644 include/cru/platform/native/window.hpp delete mode 100644 include/cru/platform/resource.hpp create mode 100644 include/cru/ui/Base.hpp create mode 100644 include/cru/ui/Control.hpp create mode 100644 include/cru/ui/Window.hpp delete mode 100644 include/cru/ui/base.hpp delete mode 100644 include/cru/ui/control.hpp create mode 100644 include/cru/ui/controls/Base.hpp create mode 100644 include/cru/ui/controls/Button.hpp create mode 100644 include/cru/ui/controls/Container.hpp delete mode 100644 include/cru/ui/controls/base.hpp delete mode 100644 include/cru/ui/controls/button.hpp delete mode 100644 include/cru/ui/controls/container.hpp create mode 100644 include/cru/ui/render/Base.hpp delete mode 100644 include/cru/ui/render/base.hpp delete mode 100644 include/cru/ui/window.hpp create mode 100644 include/cru/win/Exception.hpp create mode 100644 include/cru/win/String.hpp delete mode 100644 include/cru/win/exception.hpp create mode 100644 include/cru/win/graph/direct/Brush.hpp create mode 100644 include/cru/win/graph/direct/Exception.hpp create mode 100644 include/cru/win/graph/direct/Factory.hpp create mode 100644 include/cru/win/graph/direct/Font.hpp create mode 100644 include/cru/win/graph/direct/Geometry.hpp create mode 100644 include/cru/win/graph/direct/Painter.hpp create mode 100644 include/cru/win/graph/direct/Resource.hpp delete mode 100644 include/cru/win/graph/direct/brush.hpp delete mode 100644 include/cru/win/graph/direct/exception.hpp delete mode 100644 include/cru/win/graph/direct/factory.hpp delete mode 100644 include/cru/win/graph/direct/font.hpp delete mode 100644 include/cru/win/graph/direct/geometry.hpp delete mode 100644 include/cru/win/graph/direct/painter.hpp delete mode 100644 include/cru/win/graph/direct/resource.hpp create mode 100644 include/cru/win/native/Base.hpp create mode 100644 include/cru/win/native/Cursor.hpp create mode 100644 include/cru/win/native/Exception.hpp create mode 100644 include/cru/win/native/Keyboard.hpp create mode 100644 include/cru/win/native/Resource.hpp create mode 100644 include/cru/win/native/Window.hpp delete mode 100644 include/cru/win/native/base.hpp delete mode 100644 include/cru/win/native/cursor.hpp delete mode 100644 include/cru/win/native/exception.hpp delete mode 100644 include/cru/win/native/keyboard.hpp delete mode 100644 include/cru/win/native/resource.hpp delete mode 100644 include/cru/win/native/window.hpp delete mode 100644 include/cru/win/string.hpp (limited to 'include') diff --git a/include/cru/common/Base.hpp b/include/cru/common/Base.hpp new file mode 100644 index 00000000..ff7ab31e --- /dev/null +++ b/include/cru/common/Base.hpp @@ -0,0 +1,47 @@ +#pragma once +#include "PreConfig.hpp" + +#include + +#include + +#define CRU_UNUSED(entity) static_cast(entity); + +#define CRU_DEFAULT_COPY(classname) \ + classname(const classname&) = default; \ + classname& operator=(const classname&) = default; + +#define CRU_DEFAULT_MOVE(classname) \ + classname(classname&&) = default; \ + classname& operator=(classname&&) = default; + +#define CRU_DELETE_COPY(classname) \ + classname(const classname&) = delete; \ + classname& operator=(const classname&) = delete; + +#define CRU_DELETE_MOVE(classname) \ + classname(classname&&) = delete; \ + classname& operator=(classname&&) = delete; + +namespace cru { +class Object { + public: + Object() = default; + CRU_DEFAULT_COPY(Object) + CRU_DEFAULT_MOVE(Object) + virtual ~Object() = default; +}; + +struct Interface { + Interface() = default; + CRU_DELETE_COPY(Interface) + CRU_DELETE_MOVE(Interface) + virtual ~Interface() = default; +}; + +[[noreturn]] inline void UnreachableCode() { + throw std::runtime_error("Unreachable code."); +} + +using Index = gsl::index; +} // namespace cru diff --git a/include/cru/common/Bitmask.hpp b/include/cru/common/Bitmask.hpp new file mode 100644 index 00000000..ddfdc86b --- /dev/null +++ b/include/cru/common/Bitmask.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "Base.hpp" + +namespace cru { +template +struct Bitmask final { + using Underlying = TUnderlying; + + constexpr Bitmask() : value(0) {} + constexpr explicit Bitmask(TUnderlying value) : value(value) {} + + CRU_DEFAULT_COPY(Bitmask) + CRU_DEFAULT_MOVE(Bitmask) + + ~Bitmask() = default; + + Bitmask operator|(Bitmask rhs) const { return Bitmask(value | rhs.value); } + Bitmask operator&(Bitmask rhs) const { return Bitmask(value & rhs.value); } + Bitmask operator^(Bitmask rhs) const { return Bitmask(value ^ rhs.value); } + Bitmask operator~() const { return Bitmask(~value); } + Bitmask& operator|=(Bitmask rhs) { + value |= rhs.value; + return *this; + } + Bitmask& operator&=(Bitmask rhs) { + value &= rhs.value; + return *this; + } + Bitmask& operator^=(Bitmask rhs) { + value ^= rhs.value; + return *this; + } + + bool operator==(Bitmask rhs) const { return this->value == rhs.value; } + bool operator!=(Bitmask rhs) const { return this->value != rhs.value; } + + explicit operator TUnderlying() const { return value; } + explicit operator bool() const { return value != 0; } + + TUnderlying value; +}; +} // namespace cru diff --git a/include/cru/common/Event.hpp b/include/cru/common/Event.hpp new file mode 100644 index 00000000..377ca7f3 --- /dev/null +++ b/include/cru/common/Event.hpp @@ -0,0 +1,213 @@ +#pragma once +#include "Base.hpp" + +#include "SelfResolvable.hpp" + +#include +#include +#include +#include +#include + +namespace cru { +class EventRevoker; + +namespace details { +// Base class of all Event. +// It erases event args types and provides a +// unified form to create event revoker and +// revoke(remove) handler. +class EventBase : public SelfResolvable { + friend EventRevoker; + + protected: + using EventHandlerToken = long; + + EventBase() {} + EventBase(const EventBase& other) = delete; + EventBase(EventBase&& other) = delete; + EventBase& operator=(const EventBase& other) = delete; + EventBase& operator=(EventBase&& other) = delete; + virtual ~EventBase() = default; + + // Remove the handler with the given token. If the token + // corresponds to no handler (which might have be revoked + // before), then nothing will be done. + virtual void RemoveHandler(EventHandlerToken token) = 0; + + // Create a revoker with the given token. + inline EventRevoker CreateRevoker(EventHandlerToken token); +}; +} // namespace details + +// A non-copyable and movable event revoker. +// Call function call operator to revoke the handler. +class EventRevoker { + friend details::EventBase; + + private: + EventRevoker(ObjectResolver&& resolver, + details::EventBase::EventHandlerToken token) + : resolver_(std::move(resolver)), token_(token) {} + + public: + EventRevoker(const EventRevoker& other) = default; + EventRevoker(EventRevoker&& other) = default; + EventRevoker& operator=(const EventRevoker& other) = default; + EventRevoker& operator=(EventRevoker&& other) = default; + ~EventRevoker() = default; + + // Revoke the registered handler. If the event has already + // been destroyed, then nothing will be done. If one of the + // copies calls this, then other copies's calls will have no + // effect. (They have the same token.) + void operator()() const { + if (const auto event = resolver_.Resolve()) { + event->RemoveHandler(token_); + } + } + + private: + ObjectResolver resolver_; + details::EventBase::EventHandlerToken token_; +}; + +inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) { + return EventRevoker(CreateResolver(), token); +} + +// int -> int +// Point -> const Point& +// int& -> int& +template +using DeducedEventArgs = std::conditional_t< + std::is_lvalue_reference_v, TRaw, + std::conditional_t, TRaw, const TRaw&>>; + +// Provides an interface of event. +// IEvent only allow to add handler but not to raise the event. You may +// want to create an Event object and expose IEvent only so users won't +// be able to emit the event. +template +struct IEvent { + public: + using EventArgs = DeducedEventArgs; + using EventHandler = std::function; + + protected: + IEvent() = default; + IEvent(const IEvent& other) = delete; + IEvent(IEvent&& other) = delete; + IEvent& operator=(const IEvent& other) = delete; + IEvent& operator=(IEvent&& other) = delete; + ~IEvent() = default; // Note that user can't destroy a Event via IEvent. So + // destructor should be protected. + + public: + virtual EventRevoker AddHandler(const EventHandler& handler) = 0; + virtual EventRevoker AddHandler(EventHandler&& handler) = 0; +}; + +// A non-copyable non-movable Event class. +// It stores a list of event handlers. +template +class Event : public details::EventBase, public IEvent { + using typename IEvent::EventHandler; + + private: + struct HandlerData { + HandlerData(EventHandlerToken token, EventHandler handler) + : token(token), handler(handler) {} + EventHandlerToken token; + EventHandler handler; + }; + + public: + Event() = default; + Event(const Event&) = delete; + Event& operator=(const Event&) = delete; + Event(Event&&) = delete; + Event& operator=(Event&&) = delete; + ~Event() = default; + + EventRevoker AddHandler(const EventHandler& handler) override { + const auto token = current_token_++; + this->handler_data_list_.emplace_back(token, handler); + return CreateRevoker(token); + } + + EventRevoker AddHandler(EventHandler&& handler) override { + const auto token = current_token_++; + this->handler_data_list_.emplace_back(token, std::move(handler)); + return CreateRevoker(token); + } + + // This method will make a copy of all handlers. Because user might delete a + // handler in a handler, which may lead to seg fault as the handler is deleted + // while being executed. + // Thanks to this behavior, all handlers will be taken a snapshot when Raise + // is called, so even if you delete a handler during this period, all handlers + // in the snapshot will be executed. + void Raise(typename IEvent::EventArgs args) { + std::vector handlers; + handlers.reserve(this->handler_data_list_.size()); + for (const auto& data : this->handler_data_list_) { + handlers.push_back(data.handler); + } + for (const auto& handler : handlers) { + handler(args); + } + } + + protected: + void RemoveHandler(EventHandlerToken token) override { + const auto find_result = std::find_if( + this->handler_data_list_.cbegin(), this->handler_data_list_.cend(), + [token](const HandlerData& data) { return data.token == token; }); + if (find_result != this->handler_data_list_.cend()) { + this->handler_data_list_.erase(find_result); + } + } + + private: + std::vector handler_data_list_; + EventHandlerToken current_token_ = 0; +}; + +namespace details { +struct EventRevokerDestroyer { + void operator()(EventRevoker* p) { + (*p)(); + delete p; + } +}; +} // namespace details + +class EventRevokerGuard { + public: + EventRevokerGuard() = default; + explicit EventRevokerGuard(EventRevoker&& revoker) + : revoker_(new EventRevoker(std::move(revoker))) {} + EventRevokerGuard(const EventRevokerGuard& other) = delete; + EventRevokerGuard(EventRevokerGuard&& other) = default; + EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete; + EventRevokerGuard& operator=(EventRevokerGuard&& other) = default; + ~EventRevokerGuard() = default; + + EventRevoker Get() { + // revoker is only null when this is moved + // you shouldn't use a moved instance + Expects(revoker_); + return *revoker_; + } + + void Release() { revoker_.release(); } + + void Reset(EventRevoker&& revoker) { + revoker_.reset(new EventRevoker(std::move(revoker))); + } + + private: + std::unique_ptr revoker_; +}; // namespace cru +} // namespace cru diff --git a/include/cru/common/Logger.hpp b/include/cru/common/Logger.hpp new file mode 100644 index 00000000..bd16678b --- /dev/null +++ b/include/cru/common/Logger.hpp @@ -0,0 +1,92 @@ +#pragma once +#include "cru/common/Base.hpp" + +#include +#include +#include +#include +#include +#include + +namespace cru::log { + +enum class LogLevel { Debug, Info, Warn, Error }; + +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 StdioLogSource : public virtual ILogSource { + public: + StdioLogSource() = default; + + CRU_DELETE_COPY(StdioLogSource) + CRU_DELETE_MOVE(StdioLogSource) + + ~StdioLogSource() override = default; + + void Write(LogLevel level, const std::string_view& s) override { + // TODO: Emmm... Since it is buggy to use narrow char in UTF-8 on Windows. I + // think this implementation might be broken. (However, I didn't test it.) + // Maybe, I should detect Windows and use wide char (And I didn't test this + // either) or other more complicated implementation. Currently, I settled + // with this. + if (level == LogLevel::Error) { + std::cerr << s; + } else { + std::cout << s; + } + } +}; + +class Logger : public Object { + public: + static Logger* GetInstance(); + + public: + Logger() = default; + + CRU_DELETE_COPY(Logger) + CRU_DELETE_MOVE(Logger) + + ~Logger() override = default; + + public: + void AddSource(std::unique_ptr source); + void RemoveSource(ILogSource* source); + + public: + void Log(LogLevel level, const std::string_view& s); + + public: + std::list> sources_; +}; + +template +void Debug([[maybe_unused]] TArgs&&... args) { +#ifdef CRU_DEBUG + Logger::GetInstance()->Log(LogLevel::Debug, + fmt::format(std::forward(args)...)); +#endif +} + +template +void Info(TArgs&&... args) { + Logger::GetInstance()->Log(LogLevel::Info, + fmt::format(std::forward(args)...)); +} + +template +void Warn(TArgs&&... args) { + Logger::GetInstance()->Log(LogLevel::Warn, + fmt::format(std::forward(args)...)); +} + +template +void Error(TArgs&&... args) { + Logger::GetInstance()->Log(LogLevel::Error, + fmt::format(std::forward(args)...)); +} +} // namespace cru::log diff --git a/include/cru/common/base.hpp b/include/cru/common/base.hpp deleted file mode 100644 index ff7ab31e..00000000 --- a/include/cru/common/base.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "PreConfig.hpp" - -#include - -#include - -#define CRU_UNUSED(entity) static_cast(entity); - -#define CRU_DEFAULT_COPY(classname) \ - classname(const classname&) = default; \ - classname& operator=(const classname&) = default; - -#define CRU_DEFAULT_MOVE(classname) \ - classname(classname&&) = default; \ - classname& operator=(classname&&) = default; - -#define CRU_DELETE_COPY(classname) \ - classname(const classname&) = delete; \ - classname& operator=(const classname&) = delete; - -#define CRU_DELETE_MOVE(classname) \ - classname(classname&&) = delete; \ - classname& operator=(classname&&) = delete; - -namespace cru { -class Object { - public: - Object() = default; - CRU_DEFAULT_COPY(Object) - CRU_DEFAULT_MOVE(Object) - virtual ~Object() = default; -}; - -struct Interface { - Interface() = default; - CRU_DELETE_COPY(Interface) - CRU_DELETE_MOVE(Interface) - virtual ~Interface() = default; -}; - -[[noreturn]] inline void UnreachableCode() { - throw std::runtime_error("Unreachable code."); -} - -using Index = gsl::index; -} // namespace cru diff --git a/include/cru/common/bitmask.hpp b/include/cru/common/bitmask.hpp deleted file mode 100644 index ddfdc86b..00000000 --- a/include/cru/common/bitmask.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "Base.hpp" - -namespace cru { -template -struct Bitmask final { - using Underlying = TUnderlying; - - constexpr Bitmask() : value(0) {} - constexpr explicit Bitmask(TUnderlying value) : value(value) {} - - CRU_DEFAULT_COPY(Bitmask) - CRU_DEFAULT_MOVE(Bitmask) - - ~Bitmask() = default; - - Bitmask operator|(Bitmask rhs) const { return Bitmask(value | rhs.value); } - Bitmask operator&(Bitmask rhs) const { return Bitmask(value & rhs.value); } - Bitmask operator^(Bitmask rhs) const { return Bitmask(value ^ rhs.value); } - Bitmask operator~() const { return Bitmask(~value); } - Bitmask& operator|=(Bitmask rhs) { - value |= rhs.value; - return *this; - } - Bitmask& operator&=(Bitmask rhs) { - value &= rhs.value; - return *this; - } - Bitmask& operator^=(Bitmask rhs) { - value ^= rhs.value; - return *this; - } - - bool operator==(Bitmask rhs) const { return this->value == rhs.value; } - bool operator!=(Bitmask rhs) const { return this->value != rhs.value; } - - explicit operator TUnderlying() const { return value; } - explicit operator bool() const { return value != 0; } - - TUnderlying value; -}; -} // namespace cru diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp deleted file mode 100644 index 377ca7f3..00000000 --- a/include/cru/common/event.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#pragma once -#include "Base.hpp" - -#include "SelfResolvable.hpp" - -#include -#include -#include -#include -#include - -namespace cru { -class EventRevoker; - -namespace details { -// Base class of all Event. -// It erases event args types and provides a -// unified form to create event revoker and -// revoke(remove) handler. -class EventBase : public SelfResolvable { - friend EventRevoker; - - protected: - using EventHandlerToken = long; - - EventBase() {} - EventBase(const EventBase& other) = delete; - EventBase(EventBase&& other) = delete; - EventBase& operator=(const EventBase& other) = delete; - EventBase& operator=(EventBase&& other) = delete; - virtual ~EventBase() = default; - - // Remove the handler with the given token. If the token - // corresponds to no handler (which might have be revoked - // before), then nothing will be done. - virtual void RemoveHandler(EventHandlerToken token) = 0; - - // Create a revoker with the given token. - inline EventRevoker CreateRevoker(EventHandlerToken token); -}; -} // namespace details - -// A non-copyable and movable event revoker. -// Call function call operator to revoke the handler. -class EventRevoker { - friend details::EventBase; - - private: - EventRevoker(ObjectResolver&& resolver, - details::EventBase::EventHandlerToken token) - : resolver_(std::move(resolver)), token_(token) {} - - public: - EventRevoker(const EventRevoker& other) = default; - EventRevoker(EventRevoker&& other) = default; - EventRevoker& operator=(const EventRevoker& other) = default; - EventRevoker& operator=(EventRevoker&& other) = default; - ~EventRevoker() = default; - - // Revoke the registered handler. If the event has already - // been destroyed, then nothing will be done. If one of the - // copies calls this, then other copies's calls will have no - // effect. (They have the same token.) - void operator()() const { - if (const auto event = resolver_.Resolve()) { - event->RemoveHandler(token_); - } - } - - private: - ObjectResolver resolver_; - details::EventBase::EventHandlerToken token_; -}; - -inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) { - return EventRevoker(CreateResolver(), token); -} - -// int -> int -// Point -> const Point& -// int& -> int& -template -using DeducedEventArgs = std::conditional_t< - std::is_lvalue_reference_v, TRaw, - std::conditional_t, TRaw, const TRaw&>>; - -// Provides an interface of event. -// IEvent only allow to add handler but not to raise the event. You may -// want to create an Event object and expose IEvent only so users won't -// be able to emit the event. -template -struct IEvent { - public: - using EventArgs = DeducedEventArgs; - using EventHandler = std::function; - - protected: - IEvent() = default; - IEvent(const IEvent& other) = delete; - IEvent(IEvent&& other) = delete; - IEvent& operator=(const IEvent& other) = delete; - IEvent& operator=(IEvent&& other) = delete; - ~IEvent() = default; // Note that user can't destroy a Event via IEvent. So - // destructor should be protected. - - public: - virtual EventRevoker AddHandler(const EventHandler& handler) = 0; - virtual EventRevoker AddHandler(EventHandler&& handler) = 0; -}; - -// A non-copyable non-movable Event class. -// It stores a list of event handlers. -template -class Event : public details::EventBase, public IEvent { - using typename IEvent::EventHandler; - - private: - struct HandlerData { - HandlerData(EventHandlerToken token, EventHandler handler) - : token(token), handler(handler) {} - EventHandlerToken token; - EventHandler handler; - }; - - public: - Event() = default; - Event(const Event&) = delete; - Event& operator=(const Event&) = delete; - Event(Event&&) = delete; - Event& operator=(Event&&) = delete; - ~Event() = default; - - EventRevoker AddHandler(const EventHandler& handler) override { - const auto token = current_token_++; - this->handler_data_list_.emplace_back(token, handler); - return CreateRevoker(token); - } - - EventRevoker AddHandler(EventHandler&& handler) override { - const auto token = current_token_++; - this->handler_data_list_.emplace_back(token, std::move(handler)); - return CreateRevoker(token); - } - - // This method will make a copy of all handlers. Because user might delete a - // handler in a handler, which may lead to seg fault as the handler is deleted - // while being executed. - // Thanks to this behavior, all handlers will be taken a snapshot when Raise - // is called, so even if you delete a handler during this period, all handlers - // in the snapshot will be executed. - void Raise(typename IEvent::EventArgs args) { - std::vector handlers; - handlers.reserve(this->handler_data_list_.size()); - for (const auto& data : this->handler_data_list_) { - handlers.push_back(data.handler); - } - for (const auto& handler : handlers) { - handler(args); - } - } - - protected: - void RemoveHandler(EventHandlerToken token) override { - const auto find_result = std::find_if( - this->handler_data_list_.cbegin(), this->handler_data_list_.cend(), - [token](const HandlerData& data) { return data.token == token; }); - if (find_result != this->handler_data_list_.cend()) { - this->handler_data_list_.erase(find_result); - } - } - - private: - std::vector handler_data_list_; - EventHandlerToken current_token_ = 0; -}; - -namespace details { -struct EventRevokerDestroyer { - void operator()(EventRevoker* p) { - (*p)(); - delete p; - } -}; -} // namespace details - -class EventRevokerGuard { - public: - EventRevokerGuard() = default; - explicit EventRevokerGuard(EventRevoker&& revoker) - : revoker_(new EventRevoker(std::move(revoker))) {} - EventRevokerGuard(const EventRevokerGuard& other) = delete; - EventRevokerGuard(EventRevokerGuard&& other) = default; - EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete; - EventRevokerGuard& operator=(EventRevokerGuard&& other) = default; - ~EventRevokerGuard() = default; - - EventRevoker Get() { - // revoker is only null when this is moved - // you shouldn't use a moved instance - Expects(revoker_); - return *revoker_; - } - - void Release() { revoker_.release(); } - - void Reset(EventRevoker&& revoker) { - revoker_.reset(new EventRevoker(std::move(revoker))); - } - - private: - std::unique_ptr revoker_; -}; // namespace cru -} // namespace cru diff --git a/include/cru/common/logger.hpp b/include/cru/common/logger.hpp deleted file mode 100644 index bd16678b..00000000 --- a/include/cru/common/logger.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include "cru/common/Base.hpp" - -#include -#include -#include -#include -#include -#include - -namespace cru::log { - -enum class LogLevel { Debug, Info, Warn, Error }; - -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 StdioLogSource : public virtual ILogSource { - public: - StdioLogSource() = default; - - CRU_DELETE_COPY(StdioLogSource) - CRU_DELETE_MOVE(StdioLogSource) - - ~StdioLogSource() override = default; - - void Write(LogLevel level, const std::string_view& s) override { - // TODO: Emmm... Since it is buggy to use narrow char in UTF-8 on Windows. I - // think this implementation might be broken. (However, I didn't test it.) - // Maybe, I should detect Windows and use wide char (And I didn't test this - // either) or other more complicated implementation. Currently, I settled - // with this. - if (level == LogLevel::Error) { - std::cerr << s; - } else { - std::cout << s; - } - } -}; - -class Logger : public Object { - public: - static Logger* GetInstance(); - - public: - Logger() = default; - - CRU_DELETE_COPY(Logger) - CRU_DELETE_MOVE(Logger) - - ~Logger() override = default; - - public: - void AddSource(std::unique_ptr source); - void RemoveSource(ILogSource* source); - - public: - void Log(LogLevel level, const std::string_view& s); - - public: - std::list> sources_; -}; - -template -void Debug([[maybe_unused]] TArgs&&... args) { -#ifdef CRU_DEBUG - Logger::GetInstance()->Log(LogLevel::Debug, - fmt::format(std::forward(args)...)); -#endif -} - -template -void Info(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Info, - fmt::format(std::forward(args)...)); -} - -template -void Warn(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Warn, - fmt::format(std::forward(args)...)); -} - -template -void Error(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Error, - fmt::format(std::forward(args)...)); -} -} // namespace cru::log diff --git a/include/cru/platform/Check.hpp b/include/cru/platform/Check.hpp new file mode 100644 index 00000000..f4bbcfe8 --- /dev/null +++ b/include/cru/platform/Check.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "Exception.hpp" +#include "Resource.hpp" + +#include +#include +#include + +namespace cru::platform { +template +TTarget* CheckPlatform(INativeResource* resource, + const std::string_view& target_platform) { + Expects(resource); + const auto result = dynamic_cast(resource); + if (result == nullptr) { + throw UnsupportPlatformException(fmt::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."); + Expects(resource); + const auto result = std::dynamic_pointer_cast(resource); + if (result == nullptr) { + throw UnsupportPlatformException(fmt::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 new file mode 100644 index 00000000..8b958a1d --- /dev/null +++ b/include/cru/platform/Exception.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "cru/common/Base.hpp" + +#include + +namespace cru::platform { +class PlatformException : public std::runtime_error { + public: + using runtime_error::runtime_error; // inherit constructors +}; + +// 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. +class ReuseException : public std::runtime_error { + public: + using runtime_error::runtime_error; // inherit constructors +}; +} // namespace cru::platform diff --git a/include/cru/platform/Matrix.hpp b/include/cru/platform/Matrix.hpp new file mode 100644 index 00000000..cea5198b --- /dev/null +++ b/include/cru/platform/Matrix.hpp @@ -0,0 +1,83 @@ +#pragma once +#include "GraphBase.hpp" + +#include + +namespace cru::platform { +struct Matrix { + float m11; + float m12; + float m21; + float m22; + float m31; + float m32; + + Matrix() {} + + Matrix(float m11, float m12, float m21, float m22, float m31, float m32) { + this->m11 = m11; + this->m12 = m12; + this->m21 = m21; + this->m22 = m22; + this->m31 = m31; + this->m32 = m32; + } + + bool IsIdentity() const { + return m11 == 1.0f && m12 == 0.0f && m21 == 0.0f && m22 == 1.0f && + m31 == 0.0f && m32 == 0.0f; + } + + Matrix& operator*=(const Matrix& matrix) { + *this = Product(*this, matrix); + return *this; + } + + Matrix operator*(const Matrix& matrix) const { + return Product(*this, matrix); + } + + Point TransformPoint(const Point& point) const { + return Point{point.x * m11 + point.y * m21 + m31, + point.x * m12 + point.y * m22 + m32}; + } + + static Matrix Identity() { + return Matrix{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}; + } + + static Matrix Translation(float x, float y) { + return Matrix{1.0f, 0.0f, 0.0f, 1.0f, x, y}; + } + + static Matrix Scale(float sx, float sy) { + return Matrix{sx, 0.0f, 0.0f, sy, 0.0f, 0.0f}; + } + + static Matrix Rotation(float angle) { + float r = AngleToRadian(angle); + float s = std::sinf(r); + float c = std::cosf(r); + + return Matrix{c, s, -s, c, 0.0f, 0.0f}; + } + + static Matrix Skew(float sx, float sy) { + return Matrix{1.0f, sx, sy, 1.0f, 0.0f, 0.0f}; + } + + static Matrix Product(const Matrix& a, const Matrix& b) { + return Matrix{a.m11 * b.m11 + a.m12 * b.m21, + a.m11 * b.m12 + a.m12 * b.m22, + a.m21 * b.m11 + a.m22 * b.m21, + a.m21 * b.m12 + a.m22 * b.m22, + a.m31 * b.m11 + a.m32 * b.m21 + b.m31, + a.m31 * b.m12 + a.m32 * b.m22 + b.m32}; + } + + private: + static constexpr float PI = 3.1415926535f; + + static float AngleToRadian(float angle) { return angle / 180.f * PI; } +}; +} // namespace cru::platform diff --git a/include/cru/platform/Resource.hpp b/include/cru/platform/Resource.hpp new file mode 100644 index 00000000..72cfaf52 --- /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/check.hpp b/include/cru/platform/check.hpp deleted file mode 100644 index f4bbcfe8..00000000 --- a/include/cru/platform/check.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "Exception.hpp" -#include "Resource.hpp" - -#include -#include -#include - -namespace cru::platform { -template -TTarget* CheckPlatform(INativeResource* resource, - const std::string_view& target_platform) { - Expects(resource); - const auto result = dynamic_cast(resource); - if (result == nullptr) { - throw UnsupportPlatformException(fmt::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."); - Expects(resource); - const auto result = std::dynamic_pointer_cast(resource); - if (result == nullptr) { - throw UnsupportPlatformException(fmt::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 deleted file mode 100644 index 8b958a1d..00000000 --- a/include/cru/platform/exception.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "cru/common/Base.hpp" - -#include - -namespace cru::platform { -class PlatformException : public std::runtime_error { - public: - using runtime_error::runtime_error; // inherit constructors -}; - -// 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. -class ReuseException : public std::runtime_error { - public: - using runtime_error::runtime_error; // inherit constructors -}; -} // namespace cru::platform diff --git a/include/cru/platform/graph/Base.hpp b/include/cru/platform/graph/Base.hpp new file mode 100644 index 00000000..61cfc5ef --- /dev/null +++ b/include/cru/platform/graph/Base.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "../GraphBase.hpp" +#include "../Matrix.hpp" +#include "../Resource.hpp" + +#include + +namespace cru::platform::graph { +// forward declarations +struct IGraphFactory; +struct IBrush; +struct ISolidColorBrush; +struct IFont; +struct IGeometry; +struct IGeometryBuilder; +struct IPainter; +struct ITextLayout; + +struct TextHitTestResult { + int position; + bool trailing; + bool insideText; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/Brush.hpp b/include/cru/platform/graph/Brush.hpp new file mode 100644 index 00000000..e67384de --- /dev/null +++ b/include/cru/platform/graph/Brush.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "Resource.hpp" + +namespace cru::platform::graph { +struct IBrush : virtual IGraphResource {}; + +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..0a425d15 --- /dev/null +++ b/include/cru/platform/graph/Factory.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "Resource.hpp" + +#include "Brush.hpp" +#include "Font.hpp" +#include "Geometry.hpp" +#include "TextLayout.hpp" + +#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 new file mode 100644 index 00000000..182cc15b --- /dev/null +++ b/include/cru/platform/graph/Font.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "Resource.hpp" + +namespace cru::platform::graph { +struct IFont : virtual IGraphResource { + virtual float GetFontSize() = 0; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/Geometry.hpp b/include/cru/platform/graph/Geometry.hpp new file mode 100644 index 00000000..354efd97 --- /dev/null +++ b/include/cru/platform/graph/Geometry.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "Resource.hpp" + +namespace cru::platform::graph { +struct IGeometry : virtual IGraphResource { + virtual bool FillContains(const Point& point) = 0; +}; + +// After called Build, calling every method will throw a + +struct 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 std::unique_ptr Build() = 0; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/Painter.hpp b/include/cru/platform/graph/Painter.hpp new file mode 100644 index 00000000..27ae420b --- /dev/null +++ b/include/cru/platform/graph/Painter.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "Resource.hpp" + +namespace cru::platform::graph { + +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, IBrush* brush, + float width) = 0; + virtual void FillRectangle(const Rect& rectangle, IBrush* brush) = 0; + + virtual void StrokeGeometry(IGeometry* geometry, IBrush* brush, + float width) = 0; + virtual void FillGeometry(IGeometry* geometry, IBrush* brush) = 0; + + virtual void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) = 0; + + virtual void PushLayer(const Rect& bounds) = 0; + + virtual void PopLayer() = 0; + + virtual void EndDraw() = 0; +}; +} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/Resource.hpp b/include/cru/platform/graph/Resource.hpp new file mode 100644 index 00000000..8859360c --- /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/base.hpp b/include/cru/platform/graph/base.hpp deleted file mode 100644 index 61cfc5ef..00000000 --- a/include/cru/platform/graph/base.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "../GraphBase.hpp" -#include "../Matrix.hpp" -#include "../Resource.hpp" - -#include - -namespace cru::platform::graph { -// forward declarations -struct IGraphFactory; -struct IBrush; -struct ISolidColorBrush; -struct IFont; -struct IGeometry; -struct IGeometryBuilder; -struct IPainter; -struct ITextLayout; - -struct TextHitTestResult { - int position; - bool trailing; - bool insideText; -}; -} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/brush.hpp b/include/cru/platform/graph/brush.hpp deleted file mode 100644 index e67384de..00000000 --- a/include/cru/platform/graph/brush.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "Resource.hpp" - -namespace cru::platform::graph { -struct IBrush : virtual IGraphResource {}; - -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 deleted file mode 100644 index 0a425d15..00000000 --- a/include/cru/platform/graph/factory.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "Resource.hpp" - -#include "Brush.hpp" -#include "Font.hpp" -#include "Geometry.hpp" -#include "TextLayout.hpp" - -#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 deleted file mode 100644 index 182cc15b..00000000 --- a/include/cru/platform/graph/font.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "Resource.hpp" - -namespace cru::platform::graph { -struct IFont : virtual IGraphResource { - virtual float GetFontSize() = 0; -}; -} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/geometry.hpp b/include/cru/platform/graph/geometry.hpp deleted file mode 100644 index 354efd97..00000000 --- a/include/cru/platform/graph/geometry.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "Resource.hpp" - -namespace cru::platform::graph { -struct IGeometry : virtual IGraphResource { - virtual bool FillContains(const Point& point) = 0; -}; - -// After called Build, calling every method will throw a - -struct 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 std::unique_ptr Build() = 0; -}; -} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/painter.hpp b/include/cru/platform/graph/painter.hpp deleted file mode 100644 index 27ae420b..00000000 --- a/include/cru/platform/graph/painter.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "Resource.hpp" - -namespace cru::platform::graph { - -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, IBrush* brush, - float width) = 0; - virtual void FillRectangle(const Rect& rectangle, IBrush* brush) = 0; - - virtual void StrokeGeometry(IGeometry* geometry, IBrush* brush, - float width) = 0; - virtual void FillGeometry(IGeometry* geometry, IBrush* brush) = 0; - - virtual void DrawText(const Point& offset, ITextLayout* text_layout, - IBrush* brush) = 0; - - virtual void PushLayer(const Rect& bounds) = 0; - - virtual void PopLayer() = 0; - - virtual void EndDraw() = 0; -}; -} // namespace cru::platform::graph diff --git a/include/cru/platform/graph/resource.hpp b/include/cru/platform/graph/resource.hpp deleted file mode 100644 index 8859360c..00000000 --- a/include/cru/platform/graph/resource.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#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/util/Painter.hpp b/include/cru/platform/graph/util/Painter.hpp new file mode 100644 index 00000000..f9aec027 --- /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.hpp b/include/cru/platform/graph/util/painter.hpp deleted file mode 100644 index f9aec027..00000000 --- a/include/cru/platform/graph/util/painter.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#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/matrix.hpp b/include/cru/platform/matrix.hpp deleted file mode 100644 index cea5198b..00000000 --- a/include/cru/platform/matrix.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include "GraphBase.hpp" - -#include - -namespace cru::platform { -struct Matrix { - float m11; - float m12; - float m21; - float m22; - float m31; - float m32; - - Matrix() {} - - Matrix(float m11, float m12, float m21, float m22, float m31, float m32) { - this->m11 = m11; - this->m12 = m12; - this->m21 = m21; - this->m22 = m22; - this->m31 = m31; - this->m32 = m32; - } - - bool IsIdentity() const { - return m11 == 1.0f && m12 == 0.0f && m21 == 0.0f && m22 == 1.0f && - m31 == 0.0f && m32 == 0.0f; - } - - Matrix& operator*=(const Matrix& matrix) { - *this = Product(*this, matrix); - return *this; - } - - Matrix operator*(const Matrix& matrix) const { - return Product(*this, matrix); - } - - Point TransformPoint(const Point& point) const { - return Point{point.x * m11 + point.y * m21 + m31, - point.x * m12 + point.y * m22 + m32}; - } - - static Matrix Identity() { - return Matrix{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}; - } - - static Matrix Translation(float x, float y) { - return Matrix{1.0f, 0.0f, 0.0f, 1.0f, x, y}; - } - - static Matrix Scale(float sx, float sy) { - return Matrix{sx, 0.0f, 0.0f, sy, 0.0f, 0.0f}; - } - - static Matrix Rotation(float angle) { - float r = AngleToRadian(angle); - float s = std::sinf(r); - float c = std::cosf(r); - - return Matrix{c, s, -s, c, 0.0f, 0.0f}; - } - - static Matrix Skew(float sx, float sy) { - return Matrix{1.0f, sx, sy, 1.0f, 0.0f, 0.0f}; - } - - static Matrix Product(const Matrix& a, const Matrix& b) { - return Matrix{a.m11 * b.m11 + a.m12 * b.m21, - a.m11 * b.m12 + a.m12 * b.m22, - a.m21 * b.m11 + a.m22 * b.m21, - a.m21 * b.m12 + a.m22 * b.m22, - a.m31 * b.m11 + a.m32 * b.m21 + b.m31, - a.m31 * b.m12 + a.m32 * b.m22 + b.m32}; - } - - private: - static constexpr float PI = 3.1415926535f; - - static float AngleToRadian(float angle) { return angle / 180.f * PI; } -}; -} // namespace cru::platform diff --git a/include/cru/platform/native/Base.hpp b/include/cru/platform/native/Base.hpp new file mode 100644 index 00000000..bba7b960 --- /dev/null +++ b/include/cru/platform/native/Base.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "cru/common/Base.hpp" +#include "cru/common/Bitmask.hpp" +#include "cru/platform/graph/Base.hpp" +#include "Keyboard.hpp" + +namespace cru::platform::native { +struct ICursor; +struct ICursorManager; +struct IUiApplication; +struct INativeWindow; +struct INativeWindowResolver; +struct IInputMethodManager; +struct IInputMethodContext; + +struct Dpi { + float x; + float y; +}; + +namespace details { +struct TagMouseButton {}; +} // namespace details + +using MouseButton = Bitmask; + +namespace mouse_buttons { +constexpr MouseButton left{0b1}; +constexpr MouseButton middle{0b10}; +constexpr MouseButton right{0b100}; +} // namespace mouse_buttons + +enum class SystemCursorType { + Arrow, + Hand, +}; + +struct NativeMouseButtonEventArgs { + MouseButton button; + Point point; + KeyModifier modifier; +}; + +struct NativeKeyEventArgs { + KeyCode key; + KeyModifier modifier; +}; + +enum class FocusChangeType { Gain, Lost }; + +enum class MouseEnterLeaveType { Enter, Leave }; +} // namespace cru::platform::native diff --git a/include/cru/platform/native/Cursor.hpp b/include/cru/platform/native/Cursor.hpp new file mode 100644 index 00000000..6c8f8068 --- /dev/null +++ b/include/cru/platform/native/Cursor.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "../Resource.hpp" +#include "Base.hpp" + +#include + +namespace cru::platform::native { +struct ICursor : virtual INativeResource {}; + +struct ICursorManager : virtual INativeResource { + virtual std::shared_ptr GetSystemCursor(SystemCursorType type) = 0; + + // TODO: Add method to create cursor. +}; +} // namespace cru::platform::native diff --git a/include/cru/platform/native/Keyboard.hpp b/include/cru/platform/native/Keyboard.hpp new file mode 100644 index 00000000..26a1409d --- /dev/null +++ b/include/cru/platform/native/Keyboard.hpp @@ -0,0 +1,120 @@ +#pragma once +#include "cru/common/Bitmask.hpp" + +namespace cru::platform::native { +// Because of the complexity of keyboard layout, I only add code in US keyboard +// layout, the most widely used layout in China. We should try to make it easy +// to add new keyboard layout. +enum class KeyCode { + Unknown, + LeftButton, + MiddleButton, + RightButton, + Escape, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + N0, + N1, + N2, + N3, + N4, + N5, + N6, + N7, + N8, + N9, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + GraveAccent, + Tab, + CapsLock, + LeftShift, + LeftCtrl, + LeftSuper, + LeftAlt, + Minus, + Equal, + Backspace, + LeftSquareBracket, + RightSquareBracket, + BackSlash, + Semicolon, + Quote, + Comma, + Period, + Slash, + RightShift, + RightCtrl, + RightSuper, + RightAlt, + Insert, + Delete, + Home, + End, + PageUp, + PageDown, + Up, + Left, + Down, + Right, + PrintScreen, + ScrollLock, + Pause, + NumPad0, + NumPad1, + NumPad2, + NumPad3, + NumPad4, + NumPad5, + NumPad6, + NumPad7, + NumPad8, + NumPad9 +}; + +namespace details { +struct TagKeyModifier {}; +} // namespace details + +using KeyModifier = Bitmask; + +namespace key_modifiers { +constexpr KeyModifier shift{0b1}; +constexpr KeyModifier ctrl{0b10}; +constexpr KeyModifier alt{0b100}; +} // namespace key_modifiers +} // namespace cru::platform::native diff --git a/include/cru/platform/native/Window.hpp b/include/cru/platform/native/Window.hpp new file mode 100644 index 00000000..1fcac1fc --- /dev/null +++ b/include/cru/platform/native/Window.hpp @@ -0,0 +1,67 @@ +#pragma once +#include "../Resource.hpp" +#include "Base.hpp" +#include "cru/common/Event.hpp" + +#include + +namespace cru::platform::native { +// Represents a native window, which exposes some low-level events and +// operations. +// +// Usually you save an INativeWindowResolver after creating a window. Because +// window may be destroyed when user do certain actions like click the close +// button. Then the INativeWindow instance is destroyed and +// INativeWindowResolver::Resolve return nullptr to indicate the fact. +struct INativeWindow : virtual INativeResource { + virtual std::shared_ptr GetResolver() = 0; + + virtual void Close() = 0; + + virtual INativeWindow* GetParent() = 0; + + virtual bool IsVisible() = 0; + virtual void SetVisible(bool is_visible) = 0; + + virtual Size GetClientSize() = 0; + virtual void SetClientSize(const Size& size) = 0; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual Rect GetWindowRect() = 0; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual void SetWindowRect(const Rect& rect) = 0; + + // Relative to client lefttop. + virtual Point GetMousePosition() = 0; + + virtual bool CaptureMouse() = 0; + virtual bool ReleaseMouse() = 0; + + virtual void SetCursor(std::shared_ptr cursor) = 0; + + virtual void RequestRepaint() = 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* MouseMoveEvent() = 0; + virtual IEvent* MouseDownEvent() = 0; + virtual IEvent* MouseUpEvent() = 0; + virtual IEvent* KeyDownEvent() = 0; + virtual IEvent* KeyUpEvent() = 0; +}; + +// See INativeWindow for more info. +struct INativeWindowResolver : virtual INativeResource { + // Think twice before you save the return value. + virtual INativeWindow* Resolve() = 0; +}; +} // namespace cru::platform::native diff --git a/include/cru/platform/native/base.hpp b/include/cru/platform/native/base.hpp deleted file mode 100644 index bba7b960..00000000 --- a/include/cru/platform/native/base.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "cru/common/Base.hpp" -#include "cru/common/Bitmask.hpp" -#include "cru/platform/graph/Base.hpp" -#include "Keyboard.hpp" - -namespace cru::platform::native { -struct ICursor; -struct ICursorManager; -struct IUiApplication; -struct INativeWindow; -struct INativeWindowResolver; -struct IInputMethodManager; -struct IInputMethodContext; - -struct Dpi { - float x; - float y; -}; - -namespace details { -struct TagMouseButton {}; -} // namespace details - -using MouseButton = Bitmask; - -namespace mouse_buttons { -constexpr MouseButton left{0b1}; -constexpr MouseButton middle{0b10}; -constexpr MouseButton right{0b100}; -} // namespace mouse_buttons - -enum class SystemCursorType { - Arrow, - Hand, -}; - -struct NativeMouseButtonEventArgs { - MouseButton button; - Point point; - KeyModifier modifier; -}; - -struct NativeKeyEventArgs { - KeyCode key; - KeyModifier modifier; -}; - -enum class FocusChangeType { Gain, Lost }; - -enum class MouseEnterLeaveType { Enter, Leave }; -} // namespace cru::platform::native diff --git a/include/cru/platform/native/cursor.hpp b/include/cru/platform/native/cursor.hpp deleted file mode 100644 index 6c8f8068..00000000 --- a/include/cru/platform/native/cursor.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "../Resource.hpp" -#include "Base.hpp" - -#include - -namespace cru::platform::native { -struct ICursor : virtual INativeResource {}; - -struct ICursorManager : virtual INativeResource { - virtual std::shared_ptr GetSystemCursor(SystemCursorType type) = 0; - - // TODO: Add method to create cursor. -}; -} // namespace cru::platform::native diff --git a/include/cru/platform/native/keyboard.hpp b/include/cru/platform/native/keyboard.hpp deleted file mode 100644 index 26a1409d..00000000 --- a/include/cru/platform/native/keyboard.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include "cru/common/Bitmask.hpp" - -namespace cru::platform::native { -// Because of the complexity of keyboard layout, I only add code in US keyboard -// layout, the most widely used layout in China. We should try to make it easy -// to add new keyboard layout. -enum class KeyCode { - Unknown, - LeftButton, - MiddleButton, - RightButton, - Escape, - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - N0, - N1, - N2, - N3, - N4, - N5, - N6, - N7, - N8, - N9, - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - GraveAccent, - Tab, - CapsLock, - LeftShift, - LeftCtrl, - LeftSuper, - LeftAlt, - Minus, - Equal, - Backspace, - LeftSquareBracket, - RightSquareBracket, - BackSlash, - Semicolon, - Quote, - Comma, - Period, - Slash, - RightShift, - RightCtrl, - RightSuper, - RightAlt, - Insert, - Delete, - Home, - End, - PageUp, - PageDown, - Up, - Left, - Down, - Right, - PrintScreen, - ScrollLock, - Pause, - NumPad0, - NumPad1, - NumPad2, - NumPad3, - NumPad4, - NumPad5, - NumPad6, - NumPad7, - NumPad8, - NumPad9 -}; - -namespace details { -struct TagKeyModifier {}; -} // namespace details - -using KeyModifier = Bitmask; - -namespace key_modifiers { -constexpr KeyModifier shift{0b1}; -constexpr KeyModifier ctrl{0b10}; -constexpr KeyModifier alt{0b100}; -} // namespace key_modifiers -} // namespace cru::platform::native diff --git a/include/cru/platform/native/window.hpp b/include/cru/platform/native/window.hpp deleted file mode 100644 index 1fcac1fc..00000000 --- a/include/cru/platform/native/window.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include "../Resource.hpp" -#include "Base.hpp" -#include "cru/common/Event.hpp" - -#include - -namespace cru::platform::native { -// Represents a native window, which exposes some low-level events and -// operations. -// -// Usually you save an INativeWindowResolver after creating a window. Because -// window may be destroyed when user do certain actions like click the close -// button. Then the INativeWindow instance is destroyed and -// INativeWindowResolver::Resolve return nullptr to indicate the fact. -struct INativeWindow : virtual INativeResource { - virtual std::shared_ptr GetResolver() = 0; - - virtual void Close() = 0; - - virtual INativeWindow* GetParent() = 0; - - virtual bool IsVisible() = 0; - virtual void SetVisible(bool is_visible) = 0; - - virtual Size GetClientSize() = 0; - virtual void SetClientSize(const Size& size) = 0; - - // Get the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - virtual Rect GetWindowRect() = 0; - - // Set the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - virtual void SetWindowRect(const Rect& rect) = 0; - - // Relative to client lefttop. - virtual Point GetMousePosition() = 0; - - virtual bool CaptureMouse() = 0; - virtual bool ReleaseMouse() = 0; - - virtual void SetCursor(std::shared_ptr cursor) = 0; - - virtual void RequestRepaint() = 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* MouseMoveEvent() = 0; - virtual IEvent* MouseDownEvent() = 0; - virtual IEvent* MouseUpEvent() = 0; - virtual IEvent* KeyDownEvent() = 0; - virtual IEvent* KeyUpEvent() = 0; -}; - -// See INativeWindow for more info. -struct INativeWindowResolver : virtual INativeResource { - // Think twice before you save the return value. - virtual INativeWindow* Resolve() = 0; -}; -} // namespace cru::platform::native diff --git a/include/cru/platform/resource.hpp b/include/cru/platform/resource.hpp deleted file mode 100644 index 72cfaf52..00000000 --- a/include/cru/platform/resource.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#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/ui/Base.hpp b/include/cru/ui/Base.hpp new file mode 100644 index 00000000..b9ce0c88 --- /dev/null +++ b/include/cru/ui/Base.hpp @@ -0,0 +1,281 @@ +#pragma once +#include "cru/common/Base.hpp" +#include "cru/platform/graph/Base.hpp" +#include "cru/platform/native/Base.hpp" + +#include +#include +#include +#include + +namespace cru::ui { +//-------------------- region: import -------------------- +using cru::platform::Color; +using cru::platform::Ellipse; +using cru::platform::Matrix; +using cru::platform::Point; +using cru::platform::Rect; +using cru::platform::RoundedRect; +using cru::platform::Size; +using cru::platform::TextRange; +using cru::platform::Thickness; +using cru::platform::native::MouseButton; + +namespace mouse_buttons { +using cru::platform::native::mouse_buttons::left; +using cru::platform::native::mouse_buttons::middle; +using cru::platform::native::mouse_buttons::right; +} // namespace mouse_buttons + +namespace colors { +using cru::platform::colors::aliceblue; +using cru::platform::colors::antiquewhite; +using cru::platform::colors::aqua; +using cru::platform::colors::aquamarine; +using cru::platform::colors::azure; +using cru::platform::colors::beige; +using cru::platform::colors::bisque; +using cru::platform::colors::black; +using cru::platform::colors::blanchedalmond; +using cru::platform::colors::blue; +using cru::platform::colors::blueviolet; +using cru::platform::colors::brown; +using cru::platform::colors::burlywood; +using cru::platform::colors::cadetblue; +using cru::platform::colors::chartreuse; +using cru::platform::colors::chocolate; +using cru::platform::colors::coral; +using cru::platform::colors::cornflowerblue; +using cru::platform::colors::cornsilk; +using cru::platform::colors::crimson; +using cru::platform::colors::cyan; +using cru::platform::colors::darkblue; +using cru::platform::colors::darkcyan; +using cru::platform::colors::darkgoldenrod; +using cru::platform::colors::darkgray; +using cru::platform::colors::darkgreen; +using cru::platform::colors::darkgrey; +using cru::platform::colors::darkkhaki; +using cru::platform::colors::darkmagenta; +using cru::platform::colors::darkolivegreen; +using cru::platform::colors::darkorange; +using cru::platform::colors::darkorchid; +using cru::platform::colors::darkred; +using cru::platform::colors::darksalmon; +using cru::platform::colors::darkseagreen; +using cru::platform::colors::darkslateblue; +using cru::platform::colors::darkslategray; +using cru::platform::colors::darkslategrey; +using cru::platform::colors::darkturquoise; +using cru::platform::colors::darkviolet; +using cru::platform::colors::deeppink; +using cru::platform::colors::deepskyblue; +using cru::platform::colors::dimgray; +using cru::platform::colors::dimgrey; +using cru::platform::colors::dodgerblue; +using cru::platform::colors::firebrick; +using cru::platform::colors::floralwhite; +using cru::platform::colors::forestgreen; +using cru::platform::colors::fuchsia; +using cru::platform::colors::gainsboro; +using cru::platform::colors::ghostwhite; +using cru::platform::colors::gold; +using cru::platform::colors::goldenrod; +using cru::platform::colors::gray; +using cru::platform::colors::green; +using cru::platform::colors::greenyellow; +using cru::platform::colors::grey; +using cru::platform::colors::honeydew; +using cru::platform::colors::hotpink; +using cru::platform::colors::indianred; +using cru::platform::colors::indigo; +using cru::platform::colors::ivory; +using cru::platform::colors::khaki; +using cru::platform::colors::lavender; +using cru::platform::colors::lavenderblush; +using cru::platform::colors::lawngreen; +using cru::platform::colors::lemonchiffon; +using cru::platform::colors::lightblue; +using cru::platform::colors::lightcoral; +using cru::platform::colors::lightcyan; +using cru::platform::colors::lightgoldenrodyellow; +using cru::platform::colors::lightgray; +using cru::platform::colors::lightgreen; +using cru::platform::colors::lightgrey; +using cru::platform::colors::lightpink; +using cru::platform::colors::lightsalmon; +using cru::platform::colors::lightseagreen; +using cru::platform::colors::lightskyblue; +using cru::platform::colors::lightslategray; +using cru::platform::colors::lightslategrey; +using cru::platform::colors::lightsteelblue; +using cru::platform::colors::lightyellow; +using cru::platform::colors::lime; +using cru::platform::colors::limegreen; +using cru::platform::colors::linen; +using cru::platform::colors::magenta; +using cru::platform::colors::maroon; +using cru::platform::colors::mediumaquamarine; +using cru::platform::colors::mediumblue; +using cru::platform::colors::mediumorchid; +using cru::platform::colors::mediumpurple; +using cru::platform::colors::mediumseagreen; +using cru::platform::colors::mediumslateblue; +using cru::platform::colors::mediumspringgreen; +using cru::platform::colors::mediumturquoise; +using cru::platform::colors::mediumvioletred; +using cru::platform::colors::midnightblue; +using cru::platform::colors::mintcream; +using cru::platform::colors::mistyrose; +using cru::platform::colors::moccasin; +using cru::platform::colors::navajowhite; +using cru::platform::colors::navy; +using cru::platform::colors::oldlace; +using cru::platform::colors::olive; +using cru::platform::colors::olivedrab; +using cru::platform::colors::orange; +using cru::platform::colors::orangered; +using cru::platform::colors::orchid; +using cru::platform::colors::palegoldenrod; +using cru::platform::colors::palegreen; +using cru::platform::colors::paleturquoise; +using cru::platform::colors::palevioletred; +using cru::platform::colors::papayawhip; +using cru::platform::colors::peachpuff; +using cru::platform::colors::peru; +using cru::platform::colors::pink; +using cru::platform::colors::plum; +using cru::platform::colors::powderblue; +using cru::platform::colors::purple; +using cru::platform::colors::rebeccapurple; +using cru::platform::colors::red; +using cru::platform::colors::rosybrown; +using cru::platform::colors::royalblue; +using cru::platform::colors::saddlebrown; +using cru::platform::colors::salmon; +using cru::platform::colors::sandybrown; +using cru::platform::colors::seagreen; +using cru::platform::colors::seashell; +using cru::platform::colors::sienna; +using cru::platform::colors::silver; +using cru::platform::colors::skyblue; +using cru::platform::colors::slateblue; +using cru::platform::colors::slategray; +using cru::platform::colors::slategrey; +using cru::platform::colors::snow; +using cru::platform::colors::springgreen; +using cru::platform::colors::steelblue; +using cru::platform::colors::tan; +using cru::platform::colors::teal; +using cru::platform::colors::thistle; +using cru::platform::colors::tomato; +using cru::platform::colors::transparent; +using cru::platform::colors::turquoise; +using cru::platform::colors::violet; +using cru::platform::colors::wheat; +using cru::platform::colors::white; +using cru::platform::colors::whitesmoke; +using cru::platform::colors::yellow; +using cru::platform::colors::yellowgreen; +} // namespace colors + +//-------------------- region: forward declaration -------------------- +class Window; +class Control; +class ClickDetector; +class UiHost; + +//-------------------- region: basic types -------------------- +namespace internal { +constexpr int align_start = 0; +constexpr int align_end = align_start + 1; +constexpr int align_center = align_end + 1; +} // namespace internal + +enum class Alignment { + Start = internal::align_start, + End = internal::align_end, + Center = internal::align_center, +}; + +struct CornerRadius { + constexpr CornerRadius() + : left_top(), right_top(), left_bottom(), right_bottom() {} + constexpr CornerRadius(const float& value) + : CornerRadius(Point{value, value}) {} + constexpr CornerRadius(const Point& value) + : left_top(value), + right_top(value), + left_bottom(value), + right_bottom(value) {} + constexpr CornerRadius(Point left_top, Point right_top, Point left_bottom, + Point right_bottom) + : left_top(left_top), + right_top(right_top), + left_bottom(left_bottom), + right_bottom(right_bottom) {} + + Point left_top; + Point right_top; + Point left_bottom; + Point right_bottom; +}; + +inline bool operator==(const CornerRadius& left, const CornerRadius& right) { + return left.left_top == right.left_top && + left.left_bottom == right.left_bottom && + left.right_top == right.right_top && + left.right_bottom == right.right_bottom; +} + +inline bool operator!=(const CornerRadius& left, const CornerRadius& right) { + return !(left == right); +} + +struct BorderStyle { + std::shared_ptr border_brush; + Thickness border_thickness; + CornerRadius border_radius; + std::shared_ptr foreground_brush; + std::shared_ptr background_brush; +}; + +class CanvasPaintEventArgs { + public: + CanvasPaintEventArgs(platform::graph::IPainter* painter, + const Rect& paint_rect) + : painter_(painter), paint_rect_(paint_rect) {} + CRU_DEFAULT_COPY(CanvasPaintEventArgs) + CRU_DEFAULT_MOVE(CanvasPaintEventArgs) + ~CanvasPaintEventArgs() = default; + + platform::graph::IPainter* GetPainter() const { return painter_; } + Rect GetPaintRect() const { return paint_rect_; } + + private: + platform::graph::IPainter* painter_; + Rect paint_rect_; +}; + +enum class FlexDirection { + Horizontal, + HorizontalReverse, + Vertical, + VertivalReverse +}; + +using FlexMainAlignment = Alignment; +using FlexCrossAlignment = Alignment; + +struct FlexChildLayoutData { + float expand_factor = 0; + float shrink_factor = 1; + // nullopt stands for looking at parent's setting + std::optional cross_alignment = std::nullopt; +}; + +struct StackChildLayoutData { + Alignment horizontal = Alignment::Start; + Alignment vertical = Alignment::Start; +}; +} // namespace cru::ui diff --git a/include/cru/ui/Control.hpp b/include/cru/ui/Control.hpp new file mode 100644 index 00000000..347163be --- /dev/null +++ b/include/cru/ui/Control.hpp @@ -0,0 +1,152 @@ +#pragma once +#include "Base.hpp" + +#include "cru/common/Event.hpp" +#include "render/Base.hpp" +#include "UiEvent.hpp" + +#include + +namespace cru::ui { +class Control : public Object { + friend UiHost; + + protected: + Control(); + + public: + Control(const Control& other) = delete; + Control(Control&& other) = delete; + Control& operator=(const Control& other) = delete; + Control& operator=(Control&& other) = delete; + ~Control() override = default; + + public: + virtual std::string_view GetControlType() const = 0; + + //*************** region: tree *************** + public: + // Get the ui host if attached, otherwise, return nullptr. + UiHost* GetUiHost() const { return ui_host_; } + + Control* GetParent() const { return parent_; } + + virtual const std::vector& GetChildren() const = 0; + + // Traverse the tree rooted the control including itself. + void TraverseDescendants(const std::function& predicate); + + void _SetParent(Control* parent); + void _SetDescendantUiHost(UiHost* host); + + private: + static void _TraverseDescendants( + Control* control, const std::function& predicate); + + public: + virtual render::RenderObject* GetRenderObject() const = 0; + + //*************** region: focus *************** + public: + bool RequestFocus(); + + bool HasFocus(); + + //*************** region: mouse *************** + public: + bool IsMouseOver() const { return is_mouse_over_; } + + bool CaptureMouse(); + + bool ReleaseMouse(); + + bool IsMouseCaptured(); + + //*************** region: cursor *************** + // Cursor is inherited from parent recursively if not set. + public: + // null for not set + std::shared_ptr GetCursor(); + + // will not return nullptr + std::shared_ptr GetInheritedCursor(); + + // null to unset + void SetCursor(std::shared_ptr cursor); + + //*************** region: events *************** + public: + // Raised when mouse enter the control. Even when the control itself captures + // the mouse, this event is raised as regular. But if mouse is captured by + // another control, the control will not receive any mouse enter event. You + // can use `IsMouseCaptured` to get more info. + event::RoutedEvent* MouseEnterEvent() { + return &mouse_enter_event_; + } + // Raised when mouse is leave the control. Even when the control itself + // captures the mouse, this event is raised as regular. But if mouse is + // captured by another control, the control will not receive any mouse leave + // event. You can use `IsMouseCaptured` to get more info. + event::RoutedEvent* MouseLeaveEvent() { + return &mouse_leave_event_; + } + // Raised when mouse is move in the control. + event::RoutedEvent* MouseMoveEvent() { + return &mouse_move_event_; + } + // Raised when a mouse button is pressed in the control. + event::RoutedEvent* MouseDownEvent() { + return &mouse_down_event_; + } + // Raised when a mouse button is released in the control. + event::RoutedEvent* MouseUpEvent() { + return &mouse_up_event_; + } + event::RoutedEvent* MouseWheelEvent() { + return &mouse_wheel_event_; + } + event::RoutedEvent* KeyDownEvent() { + return &key_down_event_; + } + event::RoutedEvent* KeyUpEvent() { + return &key_up_event_; + } + event::RoutedEvent* GainFocusEvent() { + return &gain_focus_event_; + } + event::RoutedEvent* LoseFocusEvent() { + return &lose_focus_event_; + } + + private: + event::RoutedEvent mouse_enter_event_; + event::RoutedEvent mouse_leave_event_; + event::RoutedEvent mouse_move_event_; + event::RoutedEvent mouse_down_event_; + event::RoutedEvent mouse_up_event_; + event::RoutedEvent mouse_wheel_event_; + + event::RoutedEvent key_down_event_; + event::RoutedEvent key_up_event_; + + event::RoutedEvent gain_focus_event_; + event::RoutedEvent lose_focus_event_; + + //*************** region: tree *************** + protected: + virtual void OnParentChanged(Control* old_parent, Control* new_parent); + virtual void OnAttachToHost(UiHost* host); + virtual void OnDetachFromHost(UiHost* host); + + virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } + + private: + UiHost* ui_host_ = nullptr; + Control* parent_ = nullptr; + + private: + bool is_mouse_over_ = false; + + std::shared_ptr cursor_ = nullptr; +}; +} // namespace cru::ui diff --git a/include/cru/ui/Window.hpp b/include/cru/ui/Window.hpp new file mode 100644 index 00000000..eb2ecfbb --- /dev/null +++ b/include/cru/ui/Window.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "ContentControl.hpp" + +namespace cru::ui { +class Window final : public ContentControl { + friend UiHost; + + public: + static constexpr std::string_view control_type = "Window"; + + public: + static Window* CreateOverlapped(); + + private: + struct tag_overlapped_constructor {}; + + explicit Window(tag_overlapped_constructor); + + public: + Window(const Window& other) = delete; + Window(Window&& other) = delete; + Window& operator=(const Window& other) = delete; + Window& operator=(Window&& other) = delete; + ~Window() override; + + public: + std::string_view GetControlType() const final; + + render::RenderObject* GetRenderObject() const override; + + protected: + void OnChildChanged(Control* old_child, Control* new_child) override; + + private: + std::unique_ptr managed_ui_host_; + + // UiHost is responsible to take care of lifetime of this. + render::WindowRenderObject* render_object_; +}; +} // namespace cru::ui diff --git a/include/cru/ui/base.hpp b/include/cru/ui/base.hpp deleted file mode 100644 index b9ce0c88..00000000 --- a/include/cru/ui/base.hpp +++ /dev/null @@ -1,281 +0,0 @@ -#pragma once -#include "cru/common/Base.hpp" -#include "cru/platform/graph/Base.hpp" -#include "cru/platform/native/Base.hpp" - -#include -#include -#include -#include - -namespace cru::ui { -//-------------------- region: import -------------------- -using cru::platform::Color; -using cru::platform::Ellipse; -using cru::platform::Matrix; -using cru::platform::Point; -using cru::platform::Rect; -using cru::platform::RoundedRect; -using cru::platform::Size; -using cru::platform::TextRange; -using cru::platform::Thickness; -using cru::platform::native::MouseButton; - -namespace mouse_buttons { -using cru::platform::native::mouse_buttons::left; -using cru::platform::native::mouse_buttons::middle; -using cru::platform::native::mouse_buttons::right; -} // namespace mouse_buttons - -namespace colors { -using cru::platform::colors::aliceblue; -using cru::platform::colors::antiquewhite; -using cru::platform::colors::aqua; -using cru::platform::colors::aquamarine; -using cru::platform::colors::azure; -using cru::platform::colors::beige; -using cru::platform::colors::bisque; -using cru::platform::colors::black; -using cru::platform::colors::blanchedalmond; -using cru::platform::colors::blue; -using cru::platform::colors::blueviolet; -using cru::platform::colors::brown; -using cru::platform::colors::burlywood; -using cru::platform::colors::cadetblue; -using cru::platform::colors::chartreuse; -using cru::platform::colors::chocolate; -using cru::platform::colors::coral; -using cru::platform::colors::cornflowerblue; -using cru::platform::colors::cornsilk; -using cru::platform::colors::crimson; -using cru::platform::colors::cyan; -using cru::platform::colors::darkblue; -using cru::platform::colors::darkcyan; -using cru::platform::colors::darkgoldenrod; -using cru::platform::colors::darkgray; -using cru::platform::colors::darkgreen; -using cru::platform::colors::darkgrey; -using cru::platform::colors::darkkhaki; -using cru::platform::colors::darkmagenta; -using cru::platform::colors::darkolivegreen; -using cru::platform::colors::darkorange; -using cru::platform::colors::darkorchid; -using cru::platform::colors::darkred; -using cru::platform::colors::darksalmon; -using cru::platform::colors::darkseagreen; -using cru::platform::colors::darkslateblue; -using cru::platform::colors::darkslategray; -using cru::platform::colors::darkslategrey; -using cru::platform::colors::darkturquoise; -using cru::platform::colors::darkviolet; -using cru::platform::colors::deeppink; -using cru::platform::colors::deepskyblue; -using cru::platform::colors::dimgray; -using cru::platform::colors::dimgrey; -using cru::platform::colors::dodgerblue; -using cru::platform::colors::firebrick; -using cru::platform::colors::floralwhite; -using cru::platform::colors::forestgreen; -using cru::platform::colors::fuchsia; -using cru::platform::colors::gainsboro; -using cru::platform::colors::ghostwhite; -using cru::platform::colors::gold; -using cru::platform::colors::goldenrod; -using cru::platform::colors::gray; -using cru::platform::colors::green; -using cru::platform::colors::greenyellow; -using cru::platform::colors::grey; -using cru::platform::colors::honeydew; -using cru::platform::colors::hotpink; -using cru::platform::colors::indianred; -using cru::platform::colors::indigo; -using cru::platform::colors::ivory; -using cru::platform::colors::khaki; -using cru::platform::colors::lavender; -using cru::platform::colors::lavenderblush; -using cru::platform::colors::lawngreen; -using cru::platform::colors::lemonchiffon; -using cru::platform::colors::lightblue; -using cru::platform::colors::lightcoral; -using cru::platform::colors::lightcyan; -using cru::platform::colors::lightgoldenrodyellow; -using cru::platform::colors::lightgray; -using cru::platform::colors::lightgreen; -using cru::platform::colors::lightgrey; -using cru::platform::colors::lightpink; -using cru::platform::colors::lightsalmon; -using cru::platform::colors::lightseagreen; -using cru::platform::colors::lightskyblue; -using cru::platform::colors::lightslategray; -using cru::platform::colors::lightslategrey; -using cru::platform::colors::lightsteelblue; -using cru::platform::colors::lightyellow; -using cru::platform::colors::lime; -using cru::platform::colors::limegreen; -using cru::platform::colors::linen; -using cru::platform::colors::magenta; -using cru::platform::colors::maroon; -using cru::platform::colors::mediumaquamarine; -using cru::platform::colors::mediumblue; -using cru::platform::colors::mediumorchid; -using cru::platform::colors::mediumpurple; -using cru::platform::colors::mediumseagreen; -using cru::platform::colors::mediumslateblue; -using cru::platform::colors::mediumspringgreen; -using cru::platform::colors::mediumturquoise; -using cru::platform::colors::mediumvioletred; -using cru::platform::colors::midnightblue; -using cru::platform::colors::mintcream; -using cru::platform::colors::mistyrose; -using cru::platform::colors::moccasin; -using cru::platform::colors::navajowhite; -using cru::platform::colors::navy; -using cru::platform::colors::oldlace; -using cru::platform::colors::olive; -using cru::platform::colors::olivedrab; -using cru::platform::colors::orange; -using cru::platform::colors::orangered; -using cru::platform::colors::orchid; -using cru::platform::colors::palegoldenrod; -using cru::platform::colors::palegreen; -using cru::platform::colors::paleturquoise; -using cru::platform::colors::palevioletred; -using cru::platform::colors::papayawhip; -using cru::platform::colors::peachpuff; -using cru::platform::colors::peru; -using cru::platform::colors::pink; -using cru::platform::colors::plum; -using cru::platform::colors::powderblue; -using cru::platform::colors::purple; -using cru::platform::colors::rebeccapurple; -using cru::platform::colors::red; -using cru::platform::colors::rosybrown; -using cru::platform::colors::royalblue; -using cru::platform::colors::saddlebrown; -using cru::platform::colors::salmon; -using cru::platform::colors::sandybrown; -using cru::platform::colors::seagreen; -using cru::platform::colors::seashell; -using cru::platform::colors::sienna; -using cru::platform::colors::silver; -using cru::platform::colors::skyblue; -using cru::platform::colors::slateblue; -using cru::platform::colors::slategray; -using cru::platform::colors::slategrey; -using cru::platform::colors::snow; -using cru::platform::colors::springgreen; -using cru::platform::colors::steelblue; -using cru::platform::colors::tan; -using cru::platform::colors::teal; -using cru::platform::colors::thistle; -using cru::platform::colors::tomato; -using cru::platform::colors::transparent; -using cru::platform::colors::turquoise; -using cru::platform::colors::violet; -using cru::platform::colors::wheat; -using cru::platform::colors::white; -using cru::platform::colors::whitesmoke; -using cru::platform::colors::yellow; -using cru::platform::colors::yellowgreen; -} // namespace colors - -//-------------------- region: forward declaration -------------------- -class Window; -class Control; -class ClickDetector; -class UiHost; - -//-------------------- region: basic types -------------------- -namespace internal { -constexpr int align_start = 0; -constexpr int align_end = align_start + 1; -constexpr int align_center = align_end + 1; -} // namespace internal - -enum class Alignment { - Start = internal::align_start, - End = internal::align_end, - Center = internal::align_center, -}; - -struct CornerRadius { - constexpr CornerRadius() - : left_top(), right_top(), left_bottom(), right_bottom() {} - constexpr CornerRadius(const float& value) - : CornerRadius(Point{value, value}) {} - constexpr CornerRadius(const Point& value) - : left_top(value), - right_top(value), - left_bottom(value), - right_bottom(value) {} - constexpr CornerRadius(Point left_top, Point right_top, Point left_bottom, - Point right_bottom) - : left_top(left_top), - right_top(right_top), - left_bottom(left_bottom), - right_bottom(right_bottom) {} - - Point left_top; - Point right_top; - Point left_bottom; - Point right_bottom; -}; - -inline bool operator==(const CornerRadius& left, const CornerRadius& right) { - return left.left_top == right.left_top && - left.left_bottom == right.left_bottom && - left.right_top == right.right_top && - left.right_bottom == right.right_bottom; -} - -inline bool operator!=(const CornerRadius& left, const CornerRadius& right) { - return !(left == right); -} - -struct BorderStyle { - std::shared_ptr border_brush; - Thickness border_thickness; - CornerRadius border_radius; - std::shared_ptr foreground_brush; - std::shared_ptr background_brush; -}; - -class CanvasPaintEventArgs { - public: - CanvasPaintEventArgs(platform::graph::IPainter* painter, - const Rect& paint_rect) - : painter_(painter), paint_rect_(paint_rect) {} - CRU_DEFAULT_COPY(CanvasPaintEventArgs) - CRU_DEFAULT_MOVE(CanvasPaintEventArgs) - ~CanvasPaintEventArgs() = default; - - platform::graph::IPainter* GetPainter() const { return painter_; } - Rect GetPaintRect() const { return paint_rect_; } - - private: - platform::graph::IPainter* painter_; - Rect paint_rect_; -}; - -enum class FlexDirection { - Horizontal, - HorizontalReverse, - Vertical, - VertivalReverse -}; - -using FlexMainAlignment = Alignment; -using FlexCrossAlignment = Alignment; - -struct FlexChildLayoutData { - float expand_factor = 0; - float shrink_factor = 1; - // nullopt stands for looking at parent's setting - std::optional cross_alignment = std::nullopt; -}; - -struct StackChildLayoutData { - Alignment horizontal = Alignment::Start; - Alignment vertical = Alignment::Start; -}; -} // namespace cru::ui diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp deleted file mode 100644 index 347163be..00000000 --- a/include/cru/ui/control.hpp +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once -#include "Base.hpp" - -#include "cru/common/Event.hpp" -#include "render/Base.hpp" -#include "UiEvent.hpp" - -#include - -namespace cru::ui { -class Control : public Object { - friend UiHost; - - protected: - Control(); - - public: - Control(const Control& other) = delete; - Control(Control&& other) = delete; - Control& operator=(const Control& other) = delete; - Control& operator=(Control&& other) = delete; - ~Control() override = default; - - public: - virtual std::string_view GetControlType() const = 0; - - //*************** region: tree *************** - public: - // Get the ui host if attached, otherwise, return nullptr. - UiHost* GetUiHost() const { return ui_host_; } - - Control* GetParent() const { return parent_; } - - virtual const std::vector& GetChildren() const = 0; - - // Traverse the tree rooted the control including itself. - void TraverseDescendants(const std::function& predicate); - - void _SetParent(Control* parent); - void _SetDescendantUiHost(UiHost* host); - - private: - static void _TraverseDescendants( - Control* control, const std::function& predicate); - - public: - virtual render::RenderObject* GetRenderObject() const = 0; - - //*************** region: focus *************** - public: - bool RequestFocus(); - - bool HasFocus(); - - //*************** region: mouse *************** - public: - bool IsMouseOver() const { return is_mouse_over_; } - - bool CaptureMouse(); - - bool ReleaseMouse(); - - bool IsMouseCaptured(); - - //*************** region: cursor *************** - // Cursor is inherited from parent recursively if not set. - public: - // null for not set - std::shared_ptr GetCursor(); - - // will not return nullptr - std::shared_ptr GetInheritedCursor(); - - // null to unset - void SetCursor(std::shared_ptr cursor); - - //*************** region: events *************** - public: - // Raised when mouse enter the control. Even when the control itself captures - // the mouse, this event is raised as regular. But if mouse is captured by - // another control, the control will not receive any mouse enter event. You - // can use `IsMouseCaptured` to get more info. - event::RoutedEvent* MouseEnterEvent() { - return &mouse_enter_event_; - } - // Raised when mouse is leave the control. Even when the control itself - // captures the mouse, this event is raised as regular. But if mouse is - // captured by another control, the control will not receive any mouse leave - // event. You can use `IsMouseCaptured` to get more info. - event::RoutedEvent* MouseLeaveEvent() { - return &mouse_leave_event_; - } - // Raised when mouse is move in the control. - event::RoutedEvent* MouseMoveEvent() { - return &mouse_move_event_; - } - // Raised when a mouse button is pressed in the control. - event::RoutedEvent* MouseDownEvent() { - return &mouse_down_event_; - } - // Raised when a mouse button is released in the control. - event::RoutedEvent* MouseUpEvent() { - return &mouse_up_event_; - } - event::RoutedEvent* MouseWheelEvent() { - return &mouse_wheel_event_; - } - event::RoutedEvent* KeyDownEvent() { - return &key_down_event_; - } - event::RoutedEvent* KeyUpEvent() { - return &key_up_event_; - } - event::RoutedEvent* GainFocusEvent() { - return &gain_focus_event_; - } - event::RoutedEvent* LoseFocusEvent() { - return &lose_focus_event_; - } - - private: - event::RoutedEvent mouse_enter_event_; - event::RoutedEvent mouse_leave_event_; - event::RoutedEvent mouse_move_event_; - event::RoutedEvent mouse_down_event_; - event::RoutedEvent mouse_up_event_; - event::RoutedEvent mouse_wheel_event_; - - event::RoutedEvent key_down_event_; - event::RoutedEvent key_up_event_; - - event::RoutedEvent gain_focus_event_; - event::RoutedEvent lose_focus_event_; - - //*************** region: tree *************** - protected: - virtual void OnParentChanged(Control* old_parent, Control* new_parent); - virtual void OnAttachToHost(UiHost* host); - virtual void OnDetachFromHost(UiHost* host); - - virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } - - private: - UiHost* ui_host_ = nullptr; - Control* parent_ = nullptr; - - private: - bool is_mouse_over_ = false; - - std::shared_ptr cursor_ = nullptr; -}; -} // namespace cru::ui diff --git a/include/cru/ui/controls/Base.hpp b/include/cru/ui/controls/Base.hpp new file mode 100644 index 00000000..b550601b --- /dev/null +++ b/include/cru/ui/controls/Base.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "../Base.hpp" + +namespace cru::ui::controls { +using ButtonStateStyle = BorderStyle; + +struct ButtonStyle { + // corresponds to ClickState::None + ButtonStateStyle normal; + // corresponds to ClickState::Hover + ButtonStateStyle hover; + // corresponds to ClickState::Press + ButtonStateStyle press; + // corresponds to ClickState::PressInactive + ButtonStateStyle press_cancel; +}; + +struct TextBoxBorderStyle { + BorderStyle normal; + BorderStyle hover; + BorderStyle focus; + BorderStyle focus_hover; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Button.hpp b/include/cru/ui/controls/Button.hpp new file mode 100644 index 00000000..8a11409c --- /dev/null +++ b/include/cru/ui/controls/Button.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "../ContentControl.hpp" +#include "Base.hpp" + +#include "../ClickDetector.hpp" + +namespace cru::ui::controls { +class Button : public ContentControl { + public: + static constexpr std::string_view control_type = "Button"; + + static Button* Create() { return new Button(); } + + protected: + Button(); + + public: + Button(const Button& other) = delete; + Button(Button&& other) = delete; + Button& operator=(const Button& other) = delete; + Button& operator=(Button&& other) = delete; + ~Button() override; + + std::string_view GetControlType() const final { return control_type; } + + render::RenderObject* GetRenderObject() const override; + + public: + const ButtonStyle& GetStyle() const { return style_; } + void SetStyle(ButtonStyle style); + + protected: + void OnChildChanged(Control* old_child, Control* new_child) override; + + private: + std::unique_ptr render_object_{}; + + ButtonStyle style_; + + ClickDetector click_detector_; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Container.hpp b/include/cru/ui/controls/Container.hpp new file mode 100644 index 00000000..e3d78365 --- /dev/null +++ b/include/cru/ui/controls/Container.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "../ContentControl.hpp" + +namespace cru::ui::controls { +class Container : public ContentControl { + static constexpr std::string_view control_type = "Container"; + + protected: + Container(); + + public: + CRU_DELETE_COPY(Container) + CRU_DELETE_MOVE(Container) + + ~Container() override; + + public: + std::string_view GetControlType() const final { return control_type; } + + render::RenderObject* GetRenderObject() const override; + + protected: + void OnChildChanged(Control* old_child, Control* new_child) override; + + private: + std::unique_ptr render_object_; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/base.hpp b/include/cru/ui/controls/base.hpp deleted file mode 100644 index b550601b..00000000 --- a/include/cru/ui/controls/base.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "../Base.hpp" - -namespace cru::ui::controls { -using ButtonStateStyle = BorderStyle; - -struct ButtonStyle { - // corresponds to ClickState::None - ButtonStateStyle normal; - // corresponds to ClickState::Hover - ButtonStateStyle hover; - // corresponds to ClickState::Press - ButtonStateStyle press; - // corresponds to ClickState::PressInactive - ButtonStateStyle press_cancel; -}; - -struct TextBoxBorderStyle { - BorderStyle normal; - BorderStyle hover; - BorderStyle focus; - BorderStyle focus_hover; -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/button.hpp b/include/cru/ui/controls/button.hpp deleted file mode 100644 index 8a11409c..00000000 --- a/include/cru/ui/controls/button.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "../ContentControl.hpp" -#include "Base.hpp" - -#include "../ClickDetector.hpp" - -namespace cru::ui::controls { -class Button : public ContentControl { - public: - static constexpr std::string_view control_type = "Button"; - - static Button* Create() { return new Button(); } - - protected: - Button(); - - public: - Button(const Button& other) = delete; - Button(Button&& other) = delete; - Button& operator=(const Button& other) = delete; - Button& operator=(Button&& other) = delete; - ~Button() override; - - std::string_view GetControlType() const final { return control_type; } - - render::RenderObject* GetRenderObject() const override; - - public: - const ButtonStyle& GetStyle() const { return style_; } - void SetStyle(ButtonStyle style); - - protected: - void OnChildChanged(Control* old_child, Control* new_child) override; - - private: - std::unique_ptr render_object_{}; - - ButtonStyle style_; - - ClickDetector click_detector_; -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/container.hpp b/include/cru/ui/controls/container.hpp deleted file mode 100644 index e3d78365..00000000 --- a/include/cru/ui/controls/container.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "../ContentControl.hpp" - -namespace cru::ui::controls { -class Container : public ContentControl { - static constexpr std::string_view control_type = "Container"; - - protected: - Container(); - - public: - CRU_DELETE_COPY(Container) - CRU_DELETE_MOVE(Container) - - ~Container() override; - - public: - std::string_view GetControlType() const final { return control_type; } - - render::RenderObject* GetRenderObject() const override; - - protected: - void OnChildChanged(Control* old_child, Control* new_child) override; - - private: - std::unique_ptr render_object_; -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/render/Base.hpp b/include/cru/ui/render/Base.hpp new file mode 100644 index 00000000..c2af5e99 --- /dev/null +++ b/include/cru/ui/render/Base.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "../Base.hpp" + +namespace cru::ui::render { +class RenderObject; +class BorderRenderObject; +class CanvasRenderObject; +class FlexLayoutRenderObject; +class StackLayoutRenderObject; +class TextRenderObject; +class WindowRenderObject; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/base.hpp b/include/cru/ui/render/base.hpp deleted file mode 100644 index c2af5e99..00000000 --- a/include/cru/ui/render/base.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "../Base.hpp" - -namespace cru::ui::render { -class RenderObject; -class BorderRenderObject; -class CanvasRenderObject; -class FlexLayoutRenderObject; -class StackLayoutRenderObject; -class TextRenderObject; -class WindowRenderObject; -} // namespace cru::ui::render diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp deleted file mode 100644 index eb2ecfbb..00000000 --- a/include/cru/ui/window.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "ContentControl.hpp" - -namespace cru::ui { -class Window final : public ContentControl { - friend UiHost; - - public: - static constexpr std::string_view control_type = "Window"; - - public: - static Window* CreateOverlapped(); - - private: - struct tag_overlapped_constructor {}; - - explicit Window(tag_overlapped_constructor); - - public: - Window(const Window& other) = delete; - Window(Window&& other) = delete; - Window& operator=(const Window& other) = delete; - Window& operator=(Window&& other) = delete; - ~Window() override; - - public: - std::string_view GetControlType() const final; - - render::RenderObject* GetRenderObject() const override; - - protected: - void OnChildChanged(Control* old_child, Control* new_child) override; - - private: - std::unique_ptr managed_ui_host_; - - // UiHost is responsible to take care of lifetime of this. - render::WindowRenderObject* render_object_; -}; -} // namespace cru::ui diff --git a/include/cru/win/Exception.hpp b/include/cru/win/Exception.hpp new file mode 100644 index 00000000..234aea69 --- /dev/null +++ b/include/cru/win/Exception.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "WinPreConfig.hpp" + +#include "cru/platform/Exception.hpp" + +#include +#include + +namespace cru::platform::win { +class HResultError : public platform::PlatformException { + public: + explicit HResultError(HRESULT h_result); + explicit HResultError(HRESULT h_result, const std::string_view& message); + + CRU_DEFAULT_COPY(HResultError) + CRU_DEFAULT_MOVE(HResultError) + + ~HResultError() override = default; + + HRESULT GetHResult() const { return h_result_; } + + private: + HRESULT h_result_; +}; + +inline void ThrowIfFailed(const HRESULT h_result) { + if (FAILED(h_result)) throw HResultError(h_result); +} + +inline void ThrowIfFailed(const HRESULT h_result, + const std::string_view& message) { + if (FAILED(h_result)) throw HResultError(h_result, message); +} + +class Win32Error : public platform::PlatformException { + public: + // ::GetLastError is automatically called to get the error code. + // The same as Win32Error(::GetLastError(), message) + explicit Win32Error(const std::string_view& message); + Win32Error(DWORD error_code, const std::string_view& message); + + CRU_DEFAULT_COPY(Win32Error) + CRU_DEFAULT_MOVE(Win32Error) + + ~Win32Error() override = default; + + DWORD GetErrorCode() const { return error_code_; } + + private: + DWORD error_code_; +}; +} // namespace cru::platform::win diff --git a/include/cru/win/String.hpp b/include/cru/win/String.hpp new file mode 100644 index 00000000..3d68cff7 --- /dev/null +++ b/include/cru/win/String.hpp @@ -0,0 +1,107 @@ +/* +Because the text encoding problem on Windows, here I write some functions +related to text encoding. The utf-8 and utf-16 conversion function is provided +by win32 api. However win32 api does not provide any function about charactor +iteration or index by code point. (At least I haven't found.) I don't use icu +because it is not easy to build it on Windows and the bundled version in Windows +(https://docs.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-) +is only available after Windows 10 Creators Update. + +Luckily, both utf-8 and utf-16 encoding are easy to learn and program with if we +only do simple iteration rather than do much sophisticated work about +complicated error situations. (And I learn the internal of the encoding by the +way.) +*/ + +#pragma once +#include "WinPreConfig.hpp" + +#include "cru/common/Base.hpp" + +#include +#include +#include +#include + +namespace cru::platform::win { +std::string ToUtf8String(const std::wstring_view& string); +std::wstring ToUtf16String(const std::string_view& string); + +inline bool IsSurrogatePair(wchar_t c) { return c >= 0xD800 && c <= 0xDFFF; } + +inline bool IsSurrogatePairLeading(wchar_t c) { + return c >= 0xD800 && c <= 0xDBFF; +} + +inline bool IsSurrogatePairTrailing(wchar_t c) { + return c >= 0xDC00 && c <= 0xDFFF; +} + +using CodePoint = std::int32_t; +constexpr CodePoint k_code_point_end = -1; + +class TextEncodeException : public std::runtime_error { + public: + using runtime_error::runtime_error; +}; + +class Utf8Iterator : public Object { + public: + Utf8Iterator(const std::string_view& string) : string_(string) {} + + CRU_DEFAULT_COPY(Utf8Iterator) + CRU_DEFAULT_MOVE(Utf8Iterator) + + ~Utf8Iterator() = default; + + public: + void SetToHead() { position_ = 0; } + + // Advance current position and get next code point. Return k_code_point_end + // if there is no next code unit(point). Throw TextEncodeException if decoding + // fails. + CodePoint Next(); + + int CurrentPosition() const { return this->position_; } + + private: + std::string_view string_; + int position_ = 0; +}; + +class Utf16Iterator : public Object { + static_assert( + sizeof(wchar_t) == 2, + "Emmm, according to my knowledge, wchar_t should be 2-length on " + "Windows. If not, Utf16 will be broken."); + + public: + Utf16Iterator(const std::wstring_view& string) : string_(string) {} + + CRU_DEFAULT_COPY(Utf16Iterator) + CRU_DEFAULT_MOVE(Utf16Iterator) + + ~Utf16Iterator() = default; + + public: + void SetToHead() { position_ = 0; } + + // Advance current position and get next code point. Return k_code_point_end + // if there is no next code unit(point). Throw TextEncodeException if decoding + // fails. + CodePoint Next(); + + int CurrentPosition() const { return this->position_; } + + private: + std::wstring_view string_; + int position_ = 0; +}; + +int IndexUtf8ToUtf16(const std::string_view& utf8_string, int utf8_index, + const std::wstring_view& utf16_string); + +int IndexUtf16ToUtf8(const std::wstring_view& utf16_string, int utf16_index, + const std::string_view& utf8_string); + +} // namespace cru::platform::win diff --git a/include/cru/win/exception.hpp b/include/cru/win/exception.hpp deleted file mode 100644 index 234aea69..00000000 --- a/include/cru/win/exception.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "WinPreConfig.hpp" - -#include "cru/platform/Exception.hpp" - -#include -#include - -namespace cru::platform::win { -class HResultError : public platform::PlatformException { - public: - explicit HResultError(HRESULT h_result); - explicit HResultError(HRESULT h_result, const std::string_view& message); - - CRU_DEFAULT_COPY(HResultError) - CRU_DEFAULT_MOVE(HResultError) - - ~HResultError() override = default; - - HRESULT GetHResult() const { return h_result_; } - - private: - HRESULT h_result_; -}; - -inline void ThrowIfFailed(const HRESULT h_result) { - if (FAILED(h_result)) throw HResultError(h_result); -} - -inline void ThrowIfFailed(const HRESULT h_result, - const std::string_view& message) { - if (FAILED(h_result)) throw HResultError(h_result, message); -} - -class Win32Error : public platform::PlatformException { - public: - // ::GetLastError is automatically called to get the error code. - // The same as Win32Error(::GetLastError(), message) - explicit Win32Error(const std::string_view& message); - Win32Error(DWORD error_code, const std::string_view& message); - - CRU_DEFAULT_COPY(Win32Error) - CRU_DEFAULT_MOVE(Win32Error) - - ~Win32Error() override = default; - - DWORD GetErrorCode() const { return error_code_; } - - private: - DWORD error_code_; -}; -} // namespace cru::platform::win diff --git a/include/cru/win/graph/direct/Brush.hpp b/include/cru/win/graph/direct/Brush.hpp new file mode 100644 index 00000000..df1debe3 --- /dev/null +++ b/include/cru/win/graph/direct/Brush.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "ComResource.hpp" +#include "Resource.hpp" + +#include "cru/platform/graph/Brush.hpp" + +namespace cru::platform::graph::win::direct { +struct ID2DBrush : virtual IBrush { + virtual ID2D1Brush* GetD2DBrushInterface() const = 0; +}; + +class D2DSolidColorBrush : public DirectGraphResource, + public virtual ISolidColorBrush, + public virtual ID2DBrush, + public virtual IComResource { + public: + explicit D2DSolidColorBrush(DirectGraphFactory* factory); + + CRU_DELETE_COPY(D2DSolidColorBrush) + CRU_DELETE_MOVE(D2DSolidColorBrush) + + ~D2DSolidColorBrush() override = default; + + 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(); + } + + private: + Color color_ = colors::black; + + Microsoft::WRL::ComPtr brush_; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/Exception.hpp b/include/cru/win/graph/direct/Exception.hpp new file mode 100644 index 00000000..8b62e8fa --- /dev/null +++ b/include/cru/win/graph/direct/Exception.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "../../Exception.hpp" + +namespace cru::platform::graph::win::direct { +using platform::win::HResultError; +using platform::win::ThrowIfFailed; +} // namespace cru::platform::graph::win::direct \ No newline at end of file diff --git a/include/cru/win/graph/direct/Factory.hpp b/include/cru/win/graph/direct/Factory.hpp new file mode 100644 index 00000000..763d4b2b --- /dev/null +++ b/include/cru/win/graph/direct/Factory.hpp @@ -0,0 +1,58 @@ +#pragma once +#include "Resource.hpp" + +#include "cru/platform/graph/Factory.hpp" + +namespace cru::platform::graph::win::direct { +class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { + public: + DirectGraphFactory(); + + CRU_DELETE_COPY(DirectGraphFactory) + CRU_DELETE_MOVE(DirectGraphFactory) + + ~DirectGraphFactory() override; + + public: + ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } + ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.Get(); } + ID2D1Device* GetD2D1Device() const { return d2d1_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: + Microsoft::WRL::ComPtr CreateD2D1DeviceContext(); + + // This context should only be used to create graphic resources like brush. + // Because graphic resources can be shared if they are created in the same + // device. + ID2D1DeviceContext* GetDefaultD2D1DeviceContext() { + return d2d1_device_context_.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_; + // ID2D1Factory1 is a interface only available in Windows 8 and Windows 7 with + // update. It is d2d v1.1. + Microsoft::WRL::ComPtr d2d1_factory_; + Microsoft::WRL::ComPtr d2d1_device_; + 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 new file mode 100644 index 00000000..ecf9fd81 --- /dev/null +++ b/include/cru/win/graph/direct/Font.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "ComResource.hpp" +#include "Resource.hpp" + +#include "cru/platform/graph/Font.hpp" + +#include + +namespace cru::platform::graph::win::direct { +class DWriteFont : public DirectGraphResource, + public virtual IFont, + public virtual IComResource { + public: + DWriteFont(DirectGraphFactory* factory, const std::string_view& font_family, + float font_size); + + CRU_DELETE_COPY(DWriteFont) + CRU_DELETE_MOVE(DWriteFont) + + ~DWriteFont() override = default; + + public: + IDWriteTextFormat* GetComInterface() const override { + return text_format_.Get(); + } + + float GetFontSize() override; + + private: + Microsoft::WRL::ComPtr text_format_; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/Geometry.hpp b/include/cru/win/graph/direct/Geometry.hpp new file mode 100644 index 00000000..87987d3e --- /dev/null +++ b/include/cru/win/graph/direct/Geometry.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "ComResource.hpp" +#include "Resource.hpp" + +#include "cru/platform/graph/Geometry.hpp" + +namespace cru::platform::graph::win::direct { +class D2DGeometryBuilder : public DirectGraphResource, + public virtual IGeometryBuilder { + public: + explicit D2DGeometryBuilder(DirectGraphFactory* factory); + + CRU_DELETE_COPY(D2DGeometryBuilder) + CRU_DELETE_MOVE(D2DGeometryBuilder) + + ~D2DGeometryBuilder() override = default; + + public: + void BeginFigure(const Point& point) override; + void LineTo(const Point& point) override; + void QuadraticBezierTo(const Point& control_point, + const Point& end_point) override; + void CloseFigure(bool close) override; + + std::unique_ptr Build() override; + + private: + bool IsValid() { return geometry_ != nullptr; } + void CheckValidation(); + + private: + Microsoft::WRL::ComPtr geometry_; + Microsoft::WRL::ComPtr geometry_sink_; +}; + +class D2DGeometry : public DirectGraphResource, + public virtual IGeometry, + public IComResource { + public: + D2DGeometry(DirectGraphFactory* factory, + Microsoft::WRL::ComPtr geometry); + + CRU_DELETE_COPY(D2DGeometry) + CRU_DELETE_MOVE(D2DGeometry) + + ~D2DGeometry() override = default; + + public: + ID2D1Geometry* GetComInterface() const override { return geometry_.Get(); } + + public: + bool FillContains(const Point& point) override; + + private: + Microsoft::WRL::ComPtr geometry_; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/Painter.hpp b/include/cru/win/graph/direct/Painter.hpp new file mode 100644 index 00000000..a50f962d --- /dev/null +++ b/include/cru/win/graph/direct/Painter.hpp @@ -0,0 +1,60 @@ +#pragma once +#include "ComResource.hpp" +#include "Resource.hpp" + +#include "cru/platform/graph/Painter.hpp" + +#include + +namespace cru::platform::graph::win::direct { +class D2DPainter : public DirectResource, + public virtual IPainter, + public virtual IComResource { + public: + explicit D2DPainter(ID2D1RenderTarget* render_target); + + CRU_DELETE_COPY(D2DPainter) + CRU_DELETE_MOVE(D2DPainter) + + ~D2DPainter() override = default; + + public: + ID2D1RenderTarget* GetComInterface() const override { return render_target_; } + + public: + Matrix GetTransform() override; + void SetTransform(const platform::Matrix& matrix) override; + + void Clear(const Color& color) override; + + void StrokeRectangle(const Rect& rectangle, IBrush* brush, + float width) override; + void FillRectangle(const Rect& rectangle, IBrush* brush) override; + + void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; + void FillGeometry(IGeometry* geometry, IBrush* brush) override; + + void DrawText(const Point& offset, ITextLayout* text_layout, + IBrush* brush) override; + + void PushLayer(const Rect& bounds) override; + + void PopLayer() override; + + void EndDraw() override final; + + protected: + virtual void DoEndDraw() = 0; + + private: + bool IsValid() { return is_drawing_; } + void CheckValidation(); + + private: + ID2D1RenderTarget* render_target_; + + std::vector> layers_; + + bool is_drawing_ = true; +}; +} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/Resource.hpp b/include/cru/win/graph/direct/Resource.hpp new file mode 100644 index 00000000..d0a30dbd --- /dev/null +++ b/include/cru/win/graph/direct/Resource.hpp @@ -0,0 +1,49 @@ +#pragma once +#include "../../WinPreConfig.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/brush.hpp b/include/cru/win/graph/direct/brush.hpp deleted file mode 100644 index df1debe3..00000000 --- a/include/cru/win/graph/direct/brush.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include "ComResource.hpp" -#include "Resource.hpp" - -#include "cru/platform/graph/Brush.hpp" - -namespace cru::platform::graph::win::direct { -struct ID2DBrush : virtual IBrush { - virtual ID2D1Brush* GetD2DBrushInterface() const = 0; -}; - -class D2DSolidColorBrush : public DirectGraphResource, - public virtual ISolidColorBrush, - public virtual ID2DBrush, - public virtual IComResource { - public: - explicit D2DSolidColorBrush(DirectGraphFactory* factory); - - CRU_DELETE_COPY(D2DSolidColorBrush) - CRU_DELETE_MOVE(D2DSolidColorBrush) - - ~D2DSolidColorBrush() override = default; - - 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(); - } - - private: - Color color_ = colors::black; - - Microsoft::WRL::ComPtr brush_; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/exception.hpp b/include/cru/win/graph/direct/exception.hpp deleted file mode 100644 index 8b62e8fa..00000000 --- a/include/cru/win/graph/direct/exception.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "../../Exception.hpp" - -namespace cru::platform::graph::win::direct { -using platform::win::HResultError; -using platform::win::ThrowIfFailed; -} // namespace cru::platform::graph::win::direct \ No newline at end of file diff --git a/include/cru/win/graph/direct/factory.hpp b/include/cru/win/graph/direct/factory.hpp deleted file mode 100644 index 763d4b2b..00000000 --- a/include/cru/win/graph/direct/factory.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include "Resource.hpp" - -#include "cru/platform/graph/Factory.hpp" - -namespace cru::platform::graph::win::direct { -class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { - public: - DirectGraphFactory(); - - CRU_DELETE_COPY(DirectGraphFactory) - CRU_DELETE_MOVE(DirectGraphFactory) - - ~DirectGraphFactory() override; - - public: - ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } - ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.Get(); } - ID2D1Device* GetD2D1Device() const { return d2d1_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: - Microsoft::WRL::ComPtr CreateD2D1DeviceContext(); - - // This context should only be used to create graphic resources like brush. - // Because graphic resources can be shared if they are created in the same - // device. - ID2D1DeviceContext* GetDefaultD2D1DeviceContext() { - return d2d1_device_context_.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_; - // ID2D1Factory1 is a interface only available in Windows 8 and Windows 7 with - // update. It is d2d v1.1. - Microsoft::WRL::ComPtr d2d1_factory_; - Microsoft::WRL::ComPtr d2d1_device_; - 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 deleted file mode 100644 index ecf9fd81..00000000 --- a/include/cru/win/graph/direct/font.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include "ComResource.hpp" -#include "Resource.hpp" - -#include "cru/platform/graph/Font.hpp" - -#include - -namespace cru::platform::graph::win::direct { -class DWriteFont : public DirectGraphResource, - public virtual IFont, - public virtual IComResource { - public: - DWriteFont(DirectGraphFactory* factory, const std::string_view& font_family, - float font_size); - - CRU_DELETE_COPY(DWriteFont) - CRU_DELETE_MOVE(DWriteFont) - - ~DWriteFont() override = default; - - public: - IDWriteTextFormat* GetComInterface() const override { - return text_format_.Get(); - } - - float GetFontSize() override; - - private: - Microsoft::WRL::ComPtr text_format_; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/geometry.hpp b/include/cru/win/graph/direct/geometry.hpp deleted file mode 100644 index 87987d3e..00000000 --- a/include/cru/win/graph/direct/geometry.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include "ComResource.hpp" -#include "Resource.hpp" - -#include "cru/platform/graph/Geometry.hpp" - -namespace cru::platform::graph::win::direct { -class D2DGeometryBuilder : public DirectGraphResource, - public virtual IGeometryBuilder { - public: - explicit D2DGeometryBuilder(DirectGraphFactory* factory); - - CRU_DELETE_COPY(D2DGeometryBuilder) - CRU_DELETE_MOVE(D2DGeometryBuilder) - - ~D2DGeometryBuilder() override = default; - - public: - void BeginFigure(const Point& point) override; - void LineTo(const Point& point) override; - void QuadraticBezierTo(const Point& control_point, - const Point& end_point) override; - void CloseFigure(bool close) override; - - std::unique_ptr Build() override; - - private: - bool IsValid() { return geometry_ != nullptr; } - void CheckValidation(); - - private: - Microsoft::WRL::ComPtr geometry_; - Microsoft::WRL::ComPtr geometry_sink_; -}; - -class D2DGeometry : public DirectGraphResource, - public virtual IGeometry, - public IComResource { - public: - D2DGeometry(DirectGraphFactory* factory, - Microsoft::WRL::ComPtr geometry); - - CRU_DELETE_COPY(D2DGeometry) - CRU_DELETE_MOVE(D2DGeometry) - - ~D2DGeometry() override = default; - - public: - ID2D1Geometry* GetComInterface() const override { return geometry_.Get(); } - - public: - bool FillContains(const Point& point) override; - - private: - Microsoft::WRL::ComPtr geometry_; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/painter.hpp b/include/cru/win/graph/direct/painter.hpp deleted file mode 100644 index a50f962d..00000000 --- a/include/cru/win/graph/direct/painter.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include "ComResource.hpp" -#include "Resource.hpp" - -#include "cru/platform/graph/Painter.hpp" - -#include - -namespace cru::platform::graph::win::direct { -class D2DPainter : public DirectResource, - public virtual IPainter, - public virtual IComResource { - public: - explicit D2DPainter(ID2D1RenderTarget* render_target); - - CRU_DELETE_COPY(D2DPainter) - CRU_DELETE_MOVE(D2DPainter) - - ~D2DPainter() override = default; - - public: - ID2D1RenderTarget* GetComInterface() const override { return render_target_; } - - public: - Matrix GetTransform() override; - void SetTransform(const platform::Matrix& matrix) override; - - void Clear(const Color& color) override; - - void StrokeRectangle(const Rect& rectangle, IBrush* brush, - float width) override; - void FillRectangle(const Rect& rectangle, IBrush* brush) override; - - void StrokeGeometry(IGeometry* geometry, IBrush* brush, float width) override; - void FillGeometry(IGeometry* geometry, IBrush* brush) override; - - void DrawText(const Point& offset, ITextLayout* text_layout, - IBrush* brush) override; - - void PushLayer(const Rect& bounds) override; - - void PopLayer() override; - - void EndDraw() override final; - - protected: - virtual void DoEndDraw() = 0; - - private: - bool IsValid() { return is_drawing_; } - void CheckValidation(); - - private: - ID2D1RenderTarget* render_target_; - - std::vector> layers_; - - bool is_drawing_ = true; -}; -} // namespace cru::platform::graph::win::direct diff --git a/include/cru/win/graph/direct/resource.hpp b/include/cru/win/graph/direct/resource.hpp deleted file mode 100644 index d0a30dbd..00000000 --- a/include/cru/win/graph/direct/resource.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include "../../WinPreConfig.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/native/Base.hpp b/include/cru/win/native/Base.hpp new file mode 100644 index 00000000..a50c6dd1 --- /dev/null +++ b/include/cru/win/native/Base.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "../WinPreConfig.hpp" + +#include "cru/common/Base.hpp" + +namespace cru::platform::native::win { +class GodWindow; +class TimerManager; +class WinCursor; +class WinCursorManager; +class WindowClass; +class WindowManager; +class WindowRenderTarget; +class WinNativeWindow; +class WinNativeWindowResolver; +class WinUiApplication; +class WinInputMethodManager; +class WinInputMethodContextRef; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/Cursor.hpp b/include/cru/win/native/Cursor.hpp new file mode 100644 index 00000000..152374d8 --- /dev/null +++ b/include/cru/win/native/Cursor.hpp @@ -0,0 +1,47 @@ +#pragma once +#include "Resource.hpp" + +#include "cru/platform/native/Cursor.hpp" + +#include + +namespace cru::platform::native::win { +class WinCursor : public WinNativeResource, public virtual ICursor { + public: + WinCursor(HCURSOR handle, bool auto_destroy); + + CRU_DELETE_COPY(WinCursor) + CRU_DELETE_MOVE(WinCursor) + + ~WinCursor() override; + + public: + HCURSOR GetHandle() const { return handle_; } + + private: + HCURSOR handle_; + bool auto_destroy_; +}; + +class WinCursorManager : public WinNativeResource, + public virtual ICursorManager { + public: + WinCursorManager(); + + CRU_DELETE_COPY(WinCursorManager) + CRU_DELETE_MOVE(WinCursorManager) + + ~WinCursorManager() override = default; + + public: + std::shared_ptr GetSystemWinCursor(SystemCursorType type); + + std::shared_ptr GetSystemCursor(SystemCursorType type) override { + return std::static_pointer_cast(GetSystemWinCursor(type)); + } + + private: + std::shared_ptr sys_arrow_; + std::shared_ptr sys_hand_; +}; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/Exception.hpp b/include/cru/win/native/Exception.hpp new file mode 100644 index 00000000..6a5265c1 --- /dev/null +++ b/include/cru/win/native/Exception.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "../Exception.hpp" + +namespace cru::platform::native::win { +using platform::win::Win32Error; +using platform::win::HResultError; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/Keyboard.hpp b/include/cru/win/native/Keyboard.hpp new file mode 100644 index 00000000..790e0015 --- /dev/null +++ b/include/cru/win/native/Keyboard.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "Base.hpp" + +#include "cru/platform/native/Keyboard.hpp" + +namespace cru::platform::native::win { +KeyCode VirtualKeyToKeyCode(int virtual_key); +KeyModifier RetrieveKeyMofifier(); +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/Resource.hpp b/include/cru/win/native/Resource.hpp new file mode 100644 index 00000000..7afaca0f --- /dev/null +++ b/include/cru/win/native/Resource.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "Base.hpp" + +#include "cru/platform/Resource.hpp" + +namespace cru::platform::native::win { +class WinNativeResource : public Object, public virtual INativeResource { + public: + static constexpr std::string_view k_platform_id = "Windows"; + + protected: + WinNativeResource() = default; + + public: + CRU_DELETE_COPY(WinNativeResource) + CRU_DELETE_MOVE(WinNativeResource) + + ~WinNativeResource() override = default; + + public: + std::string_view GetPlatformId() const final { return k_platform_id; } +}; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/Window.hpp b/include/cru/win/native/Window.hpp new file mode 100644 index 00000000..80bee39e --- /dev/null +++ b/include/cru/win/native/Window.hpp @@ -0,0 +1,174 @@ +#pragma once +#include "Resource.hpp" + +#include "cru/platform/native/Window.hpp" +#include "WindowNativeMessageEventArgs.hpp" + +#include + +namespace cru::platform::native::win { +class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { + public: + WinNativeWindow(WinUiApplication* application, WindowClass* window_class, + DWORD window_style, WinNativeWindow* parent); + + CRU_DELETE_COPY(WinNativeWindow) + CRU_DELETE_MOVE(WinNativeWindow) + + ~WinNativeWindow() override; + + public: + std::shared_ptr GetResolver() override { + return std::static_pointer_cast(resolver_); + } + + void Close() override; + + WinNativeWindow* GetParent() override { return parent_window_; } + + bool IsVisible() override; + void SetVisible(bool is_visible) override; + + Size GetClientSize() override; + void SetClientSize(const Size& size) override; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + Rect GetWindowRect() override; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + void SetWindowRect(const Rect& rect) override; + + Point GetMousePosition() override; + + bool CaptureMouse() override; + bool ReleaseMouse() override; + + void RequestRepaint() override; + std::unique_ptr BeginPaint() override; + + void SetCursor(std::shared_ptr cursor) override; + + IEvent* DestroyEvent() override { return &destroy_event_; } + IEvent* PaintEvent() override { return &paint_event_; } + IEvent* ResizeEvent() override { return &resize_event_; } + IEvent* FocusEvent() override { return &focus_event_; } + IEvent* MouseEnterLeaveEvent() override { + return &mouse_enter_leave_event_; + } + IEvent* MouseMoveEvent() override { return &mouse_move_event_; } + IEvent* MouseDownEvent() + override { + return &mouse_down_event_; + } + IEvent* MouseUpEvent() + override { + return &mouse_up_event_; + } + IEvent* KeyDownEvent() override { + return &key_down_event_; + } + IEvent* KeyUpEvent() override { + return &key_up_event_; + } + + IEvent* NativeMessageEvent() { + return &native_message_event_; + } + + // Get the handle of the window. Return null if window is invalid. + HWND GetWindowHandle() const { return hwnd_; } + + bool HandleNativeWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, + LPARAM l_param, LRESULT* result); + + WindowRenderTarget* GetWindowRenderTarget() const { + return window_render_target_.get(); + } + + private: + // Get the client rect in pixel. + RECT GetClientRectPixel(); + + //*************** region: native messages *************** + + void OnDestroyInternal(); + void OnPaintInternal(); + void OnResizeInternal(int new_width, int new_height); + + void OnSetFocusInternal(); + void OnKillFocusInternal(); + + void OnMouseMoveInternal(POINT point); + void OnMouseLeaveInternal(); + void OnMouseDownInternal(platform::native::MouseButton button, POINT point); + void OnMouseUpInternal(platform::native::MouseButton button, POINT point); + + void OnMouseWheelInternal(short delta, POINT point); + void OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + 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; + + std::shared_ptr resolver_; + + HWND hwnd_; + WinNativeWindow* parent_window_; + + bool has_focus_ = false; + bool is_mouse_in_ = false; + + std::unique_ptr window_render_target_; + + std::shared_ptr cursor_; + + Event destroy_event_; + Event paint_event_; + Event resize_event_; + Event focus_event_; + Event mouse_enter_leave_event_; + Event mouse_move_event_; + Event mouse_down_event_; + Event mouse_up_event_; + Event key_down_event_; + Event key_up_event_; + + Event native_message_event_; +}; + +class WinNativeWindowResolver : public WinNativeResource, + public virtual INativeWindowResolver { + friend WinNativeWindow::~WinNativeWindow(); + + public: + WinNativeWindowResolver(WinNativeWindow* window) : window_(window) {} + + CRU_DELETE_COPY(WinNativeWindowResolver) + CRU_DELETE_MOVE(WinNativeWindowResolver) + + ~WinNativeWindowResolver() override = default; + + public: + INativeWindow* Resolve() override { return window_; } + + private: + void Reset(); + + private: + WinNativeWindow* window_; +}; + +WinNativeWindow* Resolve(gsl::not_null resolver); +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/base.hpp b/include/cru/win/native/base.hpp deleted file mode 100644 index a50c6dd1..00000000 --- a/include/cru/win/native/base.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "../WinPreConfig.hpp" - -#include "cru/common/Base.hpp" - -namespace cru::platform::native::win { -class GodWindow; -class TimerManager; -class WinCursor; -class WinCursorManager; -class WindowClass; -class WindowManager; -class WindowRenderTarget; -class WinNativeWindow; -class WinNativeWindowResolver; -class WinUiApplication; -class WinInputMethodManager; -class WinInputMethodContextRef; -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/cursor.hpp b/include/cru/win/native/cursor.hpp deleted file mode 100644 index 152374d8..00000000 --- a/include/cru/win/native/cursor.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "Resource.hpp" - -#include "cru/platform/native/Cursor.hpp" - -#include - -namespace cru::platform::native::win { -class WinCursor : public WinNativeResource, public virtual ICursor { - public: - WinCursor(HCURSOR handle, bool auto_destroy); - - CRU_DELETE_COPY(WinCursor) - CRU_DELETE_MOVE(WinCursor) - - ~WinCursor() override; - - public: - HCURSOR GetHandle() const { return handle_; } - - private: - HCURSOR handle_; - bool auto_destroy_; -}; - -class WinCursorManager : public WinNativeResource, - public virtual ICursorManager { - public: - WinCursorManager(); - - CRU_DELETE_COPY(WinCursorManager) - CRU_DELETE_MOVE(WinCursorManager) - - ~WinCursorManager() override = default; - - public: - std::shared_ptr GetSystemWinCursor(SystemCursorType type); - - std::shared_ptr GetSystemCursor(SystemCursorType type) override { - return std::static_pointer_cast(GetSystemWinCursor(type)); - } - - private: - std::shared_ptr sys_arrow_; - std::shared_ptr sys_hand_; -}; -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/exception.hpp b/include/cru/win/native/exception.hpp deleted file mode 100644 index 6a5265c1..00000000 --- a/include/cru/win/native/exception.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "../Exception.hpp" - -namespace cru::platform::native::win { -using platform::win::Win32Error; -using platform::win::HResultError; -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/keyboard.hpp b/include/cru/win/native/keyboard.hpp deleted file mode 100644 index 790e0015..00000000 --- a/include/cru/win/native/keyboard.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "Base.hpp" - -#include "cru/platform/native/Keyboard.hpp" - -namespace cru::platform::native::win { -KeyCode VirtualKeyToKeyCode(int virtual_key); -KeyModifier RetrieveKeyMofifier(); -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/resource.hpp b/include/cru/win/native/resource.hpp deleted file mode 100644 index 7afaca0f..00000000 --- a/include/cru/win/native/resource.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "Base.hpp" - -#include "cru/platform/Resource.hpp" - -namespace cru::platform::native::win { -class WinNativeResource : public Object, public virtual INativeResource { - public: - static constexpr std::string_view k_platform_id = "Windows"; - - protected: - WinNativeResource() = default; - - public: - CRU_DELETE_COPY(WinNativeResource) - CRU_DELETE_MOVE(WinNativeResource) - - ~WinNativeResource() override = default; - - public: - std::string_view GetPlatformId() const final { return k_platform_id; } -}; -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/window.hpp b/include/cru/win/native/window.hpp deleted file mode 100644 index 80bee39e..00000000 --- a/include/cru/win/native/window.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#pragma once -#include "Resource.hpp" - -#include "cru/platform/native/Window.hpp" -#include "WindowNativeMessageEventArgs.hpp" - -#include - -namespace cru::platform::native::win { -class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { - public: - WinNativeWindow(WinUiApplication* application, WindowClass* window_class, - DWORD window_style, WinNativeWindow* parent); - - CRU_DELETE_COPY(WinNativeWindow) - CRU_DELETE_MOVE(WinNativeWindow) - - ~WinNativeWindow() override; - - public: - std::shared_ptr GetResolver() override { - return std::static_pointer_cast(resolver_); - } - - void Close() override; - - WinNativeWindow* GetParent() override { return parent_window_; } - - bool IsVisible() override; - void SetVisible(bool is_visible) override; - - Size GetClientSize() override; - void SetClientSize(const Size& size) override; - - // Get the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - Rect GetWindowRect() override; - - // Set the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - void SetWindowRect(const Rect& rect) override; - - Point GetMousePosition() override; - - bool CaptureMouse() override; - bool ReleaseMouse() override; - - void RequestRepaint() override; - std::unique_ptr BeginPaint() override; - - void SetCursor(std::shared_ptr cursor) override; - - IEvent* DestroyEvent() override { return &destroy_event_; } - IEvent* PaintEvent() override { return &paint_event_; } - IEvent* ResizeEvent() override { return &resize_event_; } - IEvent* FocusEvent() override { return &focus_event_; } - IEvent* MouseEnterLeaveEvent() override { - return &mouse_enter_leave_event_; - } - IEvent* MouseMoveEvent() override { return &mouse_move_event_; } - IEvent* MouseDownEvent() - override { - return &mouse_down_event_; - } - IEvent* MouseUpEvent() - override { - return &mouse_up_event_; - } - IEvent* KeyDownEvent() override { - return &key_down_event_; - } - IEvent* KeyUpEvent() override { - return &key_up_event_; - } - - IEvent* NativeMessageEvent() { - return &native_message_event_; - } - - // Get the handle of the window. Return null if window is invalid. - HWND GetWindowHandle() const { return hwnd_; } - - bool HandleNativeWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, - LPARAM l_param, LRESULT* result); - - WindowRenderTarget* GetWindowRenderTarget() const { - return window_render_target_.get(); - } - - private: - // Get the client rect in pixel. - RECT GetClientRectPixel(); - - //*************** region: native messages *************** - - void OnDestroyInternal(); - void OnPaintInternal(); - void OnResizeInternal(int new_width, int new_height); - - void OnSetFocusInternal(); - void OnKillFocusInternal(); - - void OnMouseMoveInternal(POINT point); - void OnMouseLeaveInternal(); - void OnMouseDownInternal(platform::native::MouseButton button, POINT point); - void OnMouseUpInternal(platform::native::MouseButton button, POINT point); - - void OnMouseWheelInternal(short delta, POINT point); - void OnKeyDownInternal(int virtual_code); - void OnKeyUpInternal(int virtual_code); - - void OnActivatedInternal(); - void OnDeactivatedInternal(); - - 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; - - std::shared_ptr resolver_; - - HWND hwnd_; - WinNativeWindow* parent_window_; - - bool has_focus_ = false; - bool is_mouse_in_ = false; - - std::unique_ptr window_render_target_; - - std::shared_ptr cursor_; - - Event destroy_event_; - Event paint_event_; - Event resize_event_; - Event focus_event_; - Event mouse_enter_leave_event_; - Event mouse_move_event_; - Event mouse_down_event_; - Event mouse_up_event_; - Event key_down_event_; - Event key_up_event_; - - Event native_message_event_; -}; - -class WinNativeWindowResolver : public WinNativeResource, - public virtual INativeWindowResolver { - friend WinNativeWindow::~WinNativeWindow(); - - public: - WinNativeWindowResolver(WinNativeWindow* window) : window_(window) {} - - CRU_DELETE_COPY(WinNativeWindowResolver) - CRU_DELETE_MOVE(WinNativeWindowResolver) - - ~WinNativeWindowResolver() override = default; - - public: - INativeWindow* Resolve() override { return window_; } - - private: - void Reset(); - - private: - WinNativeWindow* window_; -}; - -WinNativeWindow* Resolve(gsl::not_null resolver); -} // namespace cru::platform::native::win diff --git a/include/cru/win/string.hpp b/include/cru/win/string.hpp deleted file mode 100644 index 3d68cff7..00000000 --- a/include/cru/win/string.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -Because the text encoding problem on Windows, here I write some functions -related to text encoding. The utf-8 and utf-16 conversion function is provided -by win32 api. However win32 api does not provide any function about charactor -iteration or index by code point. (At least I haven't found.) I don't use icu -because it is not easy to build it on Windows and the bundled version in Windows -(https://docs.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-) -is only available after Windows 10 Creators Update. - -Luckily, both utf-8 and utf-16 encoding are easy to learn and program with if we -only do simple iteration rather than do much sophisticated work about -complicated error situations. (And I learn the internal of the encoding by the -way.) -*/ - -#pragma once -#include "WinPreConfig.hpp" - -#include "cru/common/Base.hpp" - -#include -#include -#include -#include - -namespace cru::platform::win { -std::string ToUtf8String(const std::wstring_view& string); -std::wstring ToUtf16String(const std::string_view& string); - -inline bool IsSurrogatePair(wchar_t c) { return c >= 0xD800 && c <= 0xDFFF; } - -inline bool IsSurrogatePairLeading(wchar_t c) { - return c >= 0xD800 && c <= 0xDBFF; -} - -inline bool IsSurrogatePairTrailing(wchar_t c) { - return c >= 0xDC00 && c <= 0xDFFF; -} - -using CodePoint = std::int32_t; -constexpr CodePoint k_code_point_end = -1; - -class TextEncodeException : public std::runtime_error { - public: - using runtime_error::runtime_error; -}; - -class Utf8Iterator : public Object { - public: - Utf8Iterator(const std::string_view& string) : string_(string) {} - - CRU_DEFAULT_COPY(Utf8Iterator) - CRU_DEFAULT_MOVE(Utf8Iterator) - - ~Utf8Iterator() = default; - - public: - void SetToHead() { position_ = 0; } - - // Advance current position and get next code point. Return k_code_point_end - // if there is no next code unit(point). Throw TextEncodeException if decoding - // fails. - CodePoint Next(); - - int CurrentPosition() const { return this->position_; } - - private: - std::string_view string_; - int position_ = 0; -}; - -class Utf16Iterator : public Object { - static_assert( - sizeof(wchar_t) == 2, - "Emmm, according to my knowledge, wchar_t should be 2-length on " - "Windows. If not, Utf16 will be broken."); - - public: - Utf16Iterator(const std::wstring_view& string) : string_(string) {} - - CRU_DEFAULT_COPY(Utf16Iterator) - CRU_DEFAULT_MOVE(Utf16Iterator) - - ~Utf16Iterator() = default; - - public: - void SetToHead() { position_ = 0; } - - // Advance current position and get next code point. Return k_code_point_end - // if there is no next code unit(point). Throw TextEncodeException if decoding - // fails. - CodePoint Next(); - - int CurrentPosition() const { return this->position_; } - - private: - std::wstring_view string_; - int position_ = 0; -}; - -int IndexUtf8ToUtf16(const std::string_view& utf8_string, int utf8_index, - const std::wstring_view& utf16_string); - -int IndexUtf16ToUtf8(const std::wstring_view& utf16_string, int utf16_index, - const std::string_view& utf8_string); - -} // namespace cru::platform::win -- cgit v1.2.3