diff options
author | crupest <crupest@outlook.com> | 2021-03-24 19:14:19 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-03-24 19:14:19 +0800 |
commit | 7f15a1ff9a2007e119798053083a0a87d042990a (patch) | |
tree | cb35c01a7eaee867376d959b96c9bbd15df939e5 /include/cru/win/gui | |
parent | 74956951ee663012df0c3fe4ebe29799cb2f7732 (diff) | |
parent | 7703063a5816b089483e78ccd74bb9902ccfbea8 (diff) | |
download | cru-7f15a1ff9a2007e119798053083a0a87d042990a.tar.gz cru-7f15a1ff9a2007e119798053083a0a87d042990a.tar.bz2 cru-7f15a1ff9a2007e119798053083a0a87d042990a.zip |
Merge branch 'master' of https://github.com/crupest/CruUI
Diffstat (limited to 'include/cru/win/gui')
-rw-r--r-- | include/cru/win/gui/Base.hpp | 16 | ||||
-rw-r--r-- | include/cru/win/gui/Cursor.hpp | 50 | ||||
-rw-r--r-- | include/cru/win/gui/Exception.hpp | 7 | ||||
-rw-r--r-- | include/cru/win/gui/GodWindow.hpp | 38 | ||||
-rw-r--r-- | include/cru/win/gui/InputMethod.hpp | 87 | ||||
-rw-r--r-- | include/cru/win/gui/Keyboard.hpp | 9 | ||||
-rw-r--r-- | include/cru/win/gui/Resource.hpp | 23 | ||||
-rw-r--r-- | include/cru/win/gui/UiApplication.hpp | 74 | ||||
-rw-r--r-- | include/cru/win/gui/Window.hpp | 178 | ||||
-rw-r--r-- | include/cru/win/gui/WindowClass.hpp | 24 | ||||
-rw-r--r-- | include/cru/win/gui/WindowNativeMessageEventArgs.hpp | 40 |
11 files changed, 546 insertions, 0 deletions
diff --git a/include/cru/win/gui/Base.hpp b/include/cru/win/gui/Base.hpp new file mode 100644 index 00000000..00782663 --- /dev/null +++ b/include/cru/win/gui/Base.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "../WinPreConfig.hpp" + +#include "cru/common/Base.hpp" + +namespace cru::platform::gui::win { +class GodWindow; +class TimerManager; +class WinCursor; +class WinCursorManager; +class WindowClass; +class WindowManager; +class WinNativeWindow; +class WinUiApplication; +class WinInputMethodContext; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/Cursor.hpp b/include/cru/win/gui/Cursor.hpp new file mode 100644 index 00000000..e7c76879 --- /dev/null +++ b/include/cru/win/gui/Cursor.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "Resource.hpp" + +#include "cru/platform/gui/Cursor.hpp" + +#include <memory> + +namespace cru::platform::gui::win { +class WinCursor : public WinNativeResource, public virtual ICursor { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::WinCursor") + + 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<WinCursor> GetSystemWinCursor(SystemCursorType type); + + std::shared_ptr<ICursor> GetSystemCursor(SystemCursorType type) override { + return std::static_pointer_cast<ICursor>(GetSystemWinCursor(type)); + } + + private: + std::shared_ptr<WinCursor> sys_arrow_; + std::shared_ptr<WinCursor> sys_hand_; + std::shared_ptr<WinCursor> sys_ibeam_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/Exception.hpp b/include/cru/win/gui/Exception.hpp new file mode 100644 index 00000000..895e6c14 --- /dev/null +++ b/include/cru/win/gui/Exception.hpp @@ -0,0 +1,7 @@ +#pragma once +#include "../Exception.hpp" + +namespace cru::platform::gui::win { +using platform::win::Win32Error; +using platform::win::HResultError; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/GodWindow.hpp b/include/cru/win/gui/GodWindow.hpp new file mode 100644 index 00000000..0343b159 --- /dev/null +++ b/include/cru/win/gui/GodWindow.hpp @@ -0,0 +1,38 @@ +#pragma once +#include "Base.hpp" + +#include "WindowNativeMessageEventArgs.hpp" +#include "cru/common/Event.hpp" + +#include <memory> + +namespace cru::platform::gui::win { +class GodWindow : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::GodWindow") + + public: + explicit GodWindow(WinUiApplication* application); + + CRU_DELETE_COPY(GodWindow) + CRU_DELETE_MOVE(GodWindow) + + ~GodWindow() override; + + HWND GetHandle() const { return hwnd_; } + + bool HandleGodWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, + LPARAM l_param, LRESULT* result); + + IEvent<WindowNativeMessageEventArgs&>* MessageEvent() { + return &message_event_; + } + + private: + WinUiApplication* application_; + + std::unique_ptr<WindowClass> god_window_class_; + HWND hwnd_; + + Event<WindowNativeMessageEventArgs&> message_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/InputMethod.hpp b/include/cru/win/gui/InputMethod.hpp new file mode 100644 index 00000000..51a007d8 --- /dev/null +++ b/include/cru/win/gui/InputMethod.hpp @@ -0,0 +1,87 @@ +// Some useful information can be found from chromium code: +// https://chromium.googlesource.com/chromium/chromium/+/refs/heads/master/ui/base/win/ime_input.h +// https://chromium.googlesource.com/chromium/chromium/+/refs/heads/master/ui/base/win/ime_input.cc + +#pragma once +#include "Resource.hpp" + +#include "WindowNativeMessageEventArgs.hpp" +#include "cru/platform/gui/InputMethod.hpp" + +#include <imm.h> + +namespace cru::platform::gui::win { +class AutoHIMC : public Object { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::AutoHIMC") + + public: + explicit AutoHIMC(HWND hwnd); + + CRU_DELETE_COPY(AutoHIMC) + + AutoHIMC(AutoHIMC&& other); + AutoHIMC& operator=(AutoHIMC&& other); + + ~AutoHIMC() override; + + HWND GetHwnd() const { return hwnd_; } + + HIMC Get() const { return handle_; } + + private: + HWND hwnd_; + HIMC handle_; +}; + +class WinInputMethodContext : public WinNativeResource, + public virtual IInputMethodContext { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::WinInputMethodContext") + + public: + WinInputMethodContext(gsl::not_null<WinNativeWindow*> window); + + CRU_DELETE_COPY(WinInputMethodContext) + CRU_DELETE_MOVE(WinInputMethodContext) + + ~WinInputMethodContext() override; + + bool ShouldManuallyDrawCompositionText() override { return true; } + + void EnableIME() override; + + void DisableIME() override; + + void CompleteComposition() override; + + void CancelComposition() override; + + CompositionText GetCompositionText() override; + + void SetCandidateWindowPosition(const Point& point) override; + + IEvent<std::nullptr_t>* CompositionStartEvent() override; + + IEvent<std::nullptr_t>* CompositionEndEvent() override; + + IEvent<std::nullptr_t>* CompositionEvent() override; + + IEvent<std::u16string_view>* TextEvent() override; + + private: + void OnWindowNativeMessage(WindowNativeMessageEventArgs& args); + + std::u16string GetResultString(); + + AutoHIMC GetHIMC(); + + private: + WinNativeWindow* native_window_; + + EventRevokerListGuard event_guard_; + + Event<std::nullptr_t> composition_start_event_; + Event<std::nullptr_t> composition_end_event_; + Event<std::nullptr_t> composition_event_; + Event<std::u16string_view> text_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/Keyboard.hpp b/include/cru/win/gui/Keyboard.hpp new file mode 100644 index 00000000..5b98833c --- /dev/null +++ b/include/cru/win/gui/Keyboard.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "Base.hpp" + +#include "cru/platform/gui/Keyboard.hpp" + +namespace cru::platform::gui::win { +KeyCode VirtualKeyToKeyCode(int virtual_key); +KeyModifier RetrieveKeyMofifier(); +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/Resource.hpp b/include/cru/win/gui/Resource.hpp new file mode 100644 index 00000000..1f6f0a4a --- /dev/null +++ b/include/cru/win/gui/Resource.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "Base.hpp" + +#include "cru/platform/Resource.hpp" + +namespace cru::platform::gui::win { +class WinNativeResource : public Object, public virtual INativeResource { + public: + static constexpr std::u16string_view k_platform_id = u"Windows"; + + protected: + WinNativeResource() = default; + + public: + CRU_DELETE_COPY(WinNativeResource) + CRU_DELETE_MOVE(WinNativeResource) + + ~WinNativeResource() override = default; + + public: + std::u16string_view GetPlatformId() const final { return k_platform_id; } +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/UiApplication.hpp b/include/cru/win/gui/UiApplication.hpp new file mode 100644 index 00000000..4cf46858 --- /dev/null +++ b/include/cru/win/gui/UiApplication.hpp @@ -0,0 +1,74 @@ +#pragma once +#include "Resource.hpp" + +#include "cru/platform/gui/Base.hpp" +#include "cru/platform/gui/UiApplication.hpp" + +#include <memory> + +namespace cru::platform::graphics::win::direct { +class DirectGraphFactory; +} + +namespace cru::platform::gui::win { +class WinUiApplication : public WinNativeResource, + public virtual IUiApplication { + public: + static WinUiApplication* GetInstance() { return instance; } + + private: + static WinUiApplication* instance; + + public: + WinUiApplication(); + + CRU_DELETE_COPY(WinUiApplication) + CRU_DELETE_MOVE(WinUiApplication) + + ~WinUiApplication() override; + + public: + int Run() override; + void RequestQuit(int quit_code) override; + + void AddOnQuitHandler(std::function<void()> handler) override; + + long long SetImmediate(std::function<void()> action) override; + long long SetTimeout(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + long long SetInterval(std::chrono::milliseconds milliseconds, + std::function<void()> action) override; + void CancelTimer(long long id) override; + + std::vector<INativeWindow*> GetAllWindow() override; + INativeWindow* CreateWindow(INativeWindow* parent, CreateWindowFlag flag) override; + + cru::platform::graphics::IGraphFactory* GetGraphFactory() override; + + cru::platform::graphics::win::direct::DirectGraphFactory* GetDirectFactory() { + return graph_factory_.get(); + } + + ICursorManager* GetCursorManager() override; + + HINSTANCE GetInstanceHandle() const { return instance_handle_; } + + GodWindow* GetGodWindow() const { return god_window_.get(); } + TimerManager* GetTimerManager() const { return timer_manager_.get(); } + WindowManager* GetWindowManager() const { return window_manager_.get(); } + + private: + HINSTANCE instance_handle_; + + std::unique_ptr<cru::platform::graphics::win::direct::DirectGraphFactory> + graph_factory_; + + std::unique_ptr<GodWindow> god_window_; + std::unique_ptr<TimerManager> timer_manager_; + std::unique_ptr<WindowManager> window_manager_; + + std::unique_ptr<WinCursorManager> cursor_manager_; + + std::vector<std::function<void()>> quit_handlers_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/Window.hpp b/include/cru/win/gui/Window.hpp new file mode 100644 index 00000000..3ba9ef68 --- /dev/null +++ b/include/cru/win/gui/Window.hpp @@ -0,0 +1,178 @@ +#pragma once +#include "Resource.hpp" + +#include "WindowNativeMessageEventArgs.hpp" +#include "cru/platform/GraphBase.hpp" +#include "cru/platform/gui/Base.hpp" +#include "cru/platform/gui/Window.hpp" +#include "cru/win/graphics/direct/WindowRenderTarget.hpp" + +#include <memory> + +namespace cru::platform::gui::win { +class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::platform::gui::win::WinNativeWindow") + + public: + WinNativeWindow(WinUiApplication* application, WindowClass* window_class, + DWORD window_style, WinNativeWindow* parent); + + CRU_DELETE_COPY(WinNativeWindow) + CRU_DELETE_MOVE(WinNativeWindow) + + ~WinNativeWindow() override; + + public: + 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<graphics::IPainter> BeginPaint() override; + + void SetCursor(std::shared_ptr<ICursor> cursor) override; + + IEvent<std::nullptr_t>* DestroyEvent() override { return &destroy_event_; } + IEvent<std::nullptr_t>* PaintEvent() override { return &paint_event_; } + IEvent<Size>* ResizeEvent() override { return &resize_event_; } + IEvent<FocusChangeType>* FocusEvent() override { return &focus_event_; } + IEvent<MouseEnterLeaveType>* MouseEnterLeaveEvent() override { + return &mouse_enter_leave_event_; + } + IEvent<Point>* MouseMoveEvent() override { return &mouse_move_event_; } + IEvent<platform::gui::NativeMouseButtonEventArgs>* MouseDownEvent() + override { + return &mouse_down_event_; + } + IEvent<platform::gui::NativeMouseButtonEventArgs>* MouseUpEvent() + override { + return &mouse_up_event_; + } + IEvent<platform::gui::NativeKeyEventArgs>* KeyDownEvent() override { + return &key_down_event_; + } + IEvent<platform::gui::NativeKeyEventArgs>* KeyUpEvent() override { + return &key_up_event_; + } + + IEvent<WindowNativeMessageEventArgs&>* NativeMessageEvent() { + return &native_message_event_; + } + + IInputMethodContext* GetInputMethodContext() override; + + // 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); + + graphics::win::direct::D2DWindowRenderTarget* GetWindowRenderTarget() const { + return window_render_target_.get(); + } + + //*************** region: dpi *************** + float GetDpi() const { return dpi_; } + + inline int DipToPixel(const float dip) { + return static_cast<int>(dip * GetDpi() / 96.0f); + } + + inline POINT DipToPixel(const Point& dip_point) { + POINT result; + result.x = DipToPixel(dip_point.x); + result.y = DipToPixel(dip_point.y); + return result; + } + + inline float PixelToDip(const int pixel) { + return static_cast<float>(pixel) * 96.0f / GetDpi(); + } + + inline Point PixelToDip(const POINT& pi_point) { + return Point(PixelToDip(pi_point.x), PixelToDip(pi_point.y)); + } + + 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::gui::MouseButton button, POINT point); + void OnMouseUpInternal(platform::gui::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; + + HWND hwnd_; + WinNativeWindow* parent_window_; + + float dpi_; + + bool has_focus_ = false; + bool is_mouse_in_ = false; + + std::unique_ptr<graphics::win::direct::D2DWindowRenderTarget> + window_render_target_; + + std::shared_ptr<WinCursor> cursor_; + + std::unique_ptr<WinInputMethodContext> input_method_context_; + + Event<std::nullptr_t> destroy_event_; + Event<std::nullptr_t> paint_event_; + Event<Size> resize_event_; + Event<FocusChangeType> focus_event_; + Event<MouseEnterLeaveType> mouse_enter_leave_event_; + Event<Point> mouse_move_event_; + Event<platform::gui::NativeMouseButtonEventArgs> mouse_down_event_; + Event<platform::gui::NativeMouseButtonEventArgs> mouse_up_event_; + Event<platform::gui::NativeKeyEventArgs> key_down_event_; + Event<platform::gui::NativeKeyEventArgs> key_up_event_; + + Event<WindowNativeMessageEventArgs&> native_message_event_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/WindowClass.hpp b/include/cru/win/gui/WindowClass.hpp new file mode 100644 index 00000000..2c07b68f --- /dev/null +++ b/include/cru/win/gui/WindowClass.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "Base.hpp" + +#include <string> + +namespace cru::platform::gui::win { +class WindowClass : public Object { + public: + WindowClass(std::wstring name, WNDPROC window_proc, HINSTANCE h_instance); + + CRU_DELETE_COPY(WindowClass) + CRU_DELETE_MOVE(WindowClass) + + ~WindowClass() override = default; + + const wchar_t* GetName() const { return name_.c_str(); } + + ATOM GetAtom() const { return atom_; } + + private: + std::wstring name_; + ATOM atom_; +}; +} // namespace cru::platform::gui::win diff --git a/include/cru/win/gui/WindowNativeMessageEventArgs.hpp b/include/cru/win/gui/WindowNativeMessageEventArgs.hpp new file mode 100644 index 00000000..834ba3c2 --- /dev/null +++ b/include/cru/win/gui/WindowNativeMessageEventArgs.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "../WinPreConfig.hpp" + +#include "cru/common/Base.hpp" + +namespace cru::platform::gui::win { +struct WindowNativeMessage { + HWND hwnd; + UINT msg; + WPARAM w_param; + LPARAM l_param; +}; + +class WindowNativeMessageEventArgs : public Object { + public: + WindowNativeMessageEventArgs(const WindowNativeMessage& message) + : message_(message) {} + CRU_DEFAULT_COPY(WindowNativeMessageEventArgs) + CRU_DEFAULT_MOVE(WindowNativeMessageEventArgs) + ~WindowNativeMessageEventArgs() override = default; + + const WindowNativeMessage& GetWindowMessage() const { return message_; } + + LRESULT GetResult() const { return result_; } + void SetResult(LRESULT result) { result_ = result; } + + bool IsHandled() const { return handled_; } + void SetHandled(bool handled) { handled_ = handled; } + + void HandleWithResult(LRESULT result) { + handled_ = true; + result_ = result; + } + + private: + WindowNativeMessage message_; + LRESULT result_; + bool handled_ = false; +}; +} // namespace cru::platform::gui::win |