diff options
author | crupest <crupest@outlook.com> | 2018-09-13 00:14:59 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-09-13 00:14:59 +0800 |
commit | 5f35ba198582bb93e16d34c8d94ffdc8f453068d (patch) | |
tree | 9ac9865ff3f058d688240abff8b7a44c876dd32a | |
parent | bbcd0257150d967bdccd3ab89c100d02bd7a23d3 (diff) | |
download | cru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.tar.gz cru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.tar.bz2 cru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.zip |
...
-rw-r--r-- | CruUI/application.cpp | 125 | ||||
-rw-r--r-- | CruUI/application.h | 39 | ||||
-rw-r--r-- | CruUI/timer.cpp | 2 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.cpp | 25 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.h | 3 |
5 files changed, 127 insertions, 67 deletions
diff --git a/CruUI/application.cpp b/CruUI/application.cpp index c60bb043..04b18ff0 100644 --- a/CruUI/application.cpp +++ b/CruUI/application.cpp @@ -10,78 +10,46 @@ namespace cru { constexpr auto god_window_class_name = L"GodWindowClass"; constexpr int invoke_later_message_id = WM_USER + 2000; - Application* Application::instance_ = nullptr; - Application * Application::GetInstance() { - return instance_; - } - - Application::Application(HINSTANCE h_instance) - : h_instance_(h_instance) { + LRESULT GodWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + const auto app = Application::GetInstance(); - if (instance_) - throw std::runtime_error("A application instance already exists."); + if (app) + { + const auto result = app->GetGodWindow()->HandleGodWindowMessage(hWnd, uMsg, wParam, lParam); + if (result.has_value()) + return result.value(); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } - instance_ = this; + GodWindow::GodWindow(Application* application) : application_(application) + { + const auto h_instance = application->GetInstanceHandle(); god_window_class_ = std::make_unique<ui::WindowClass>(god_window_class_name, GodWndProc, h_instance); - const auto hwnd = CreateWindowEx(0, + hwnd_ = CreateWindowEx(0, god_window_class_name, L"", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, h_instance, nullptr ); - if (hwnd == nullptr) + if (hwnd_ == nullptr) throw std::runtime_error("Failed to create window."); - - god_hwnd_ = hwnd; - - window_manager_ = std::make_unique<ui::WindowManager>(); - graph_manager_ = std::make_unique<graph::GraphManager>(); - timer_manager_ = std::make_unique<TimerManager>(); } - Application::~Application() + GodWindow::~GodWindow() { - instance_ = nullptr; + ::DestroyWindow(hwnd_); } - int Application::Run() - { - MSG msg; - - while (GetMessage(&msg, nullptr, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return static_cast<int>(msg.wParam); - } - - void Application::Quit(const int quit_code) { - ::PostQuitMessage(quit_code); - } - - LRESULT Application::GodWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) - { - const auto app = Application::GetInstance(); - - if (app) - { - const auto result = app->HandleGodWindowMessage(hWnd, Msg, wParam, lParam); - if (result.has_value()) - return result.value(); - else - return DefWindowProc(hWnd, Msg, wParam, lParam); - } - else - return DefWindowProc(hWnd, Msg, wParam, lParam); - } - - std::optional<LRESULT> Application::HandleGodWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param) + std::optional<LRESULT> GodWindow::HandleGodWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param) { switch (msg) { @@ -94,7 +62,7 @@ namespace cru { } case WM_TIMER: { - const auto action = GetTimerManager()->GetAction(static_cast<UINT_PTR>(w_param)); + const auto action = application_->GetTimerManager()->GetAction(static_cast<UINT_PTR>(w_param)); if (action.has_value()) { action.value()(); @@ -108,11 +76,56 @@ namespace cru { return std::nullopt; } + + + Application* Application::instance_ = nullptr; + + Application * Application::GetInstance() { + return instance_; + } + + Application::Application(HINSTANCE h_instance) + : h_instance_(h_instance) { + + if (instance_) + throw std::runtime_error("A application instance already exists."); + + instance_ = this; + + window_manager_ = std::make_unique<ui::WindowManager>(); + graph_manager_ = std::make_unique<graph::GraphManager>(); + timer_manager_ = std::make_unique<TimerManager>(); + + god_window_ = std::make_unique<GodWindow>(this); + } + + Application::~Application() + { + instance_ = nullptr; + } + + int Application::Run() + { + MSG msg; + + while (GetMessage(&msg, nullptr, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return static_cast<int>(msg.wParam); + } + + void Application::Quit(const int quit_code) { + ::PostQuitMessage(quit_code); + } + void InvokeLater(InvokeLaterAction&& action) { //copy the action to a safe place auto p_action_copy = new InvokeLaterAction(std::move(action)); - if (PostMessageW(Application::GetInstance()->GetGodWindowHandle(), invoke_later_message_id, reinterpret_cast<WPARAM>(p_action_copy), 0) == 0) + if (PostMessageW(Application::GetInstance()->GetGodWindow()->GetHandle(), invoke_later_message_id, reinterpret_cast<WPARAM>(p_action_copy), 0) == 0) throw std::runtime_error(fmt::format("Last error: {}.", ::GetLastError())); } } diff --git a/CruUI/application.h b/CruUI/application.h index 4285cc21..fe0d431c 100644 --- a/CruUI/application.h +++ b/CruUI/application.h @@ -8,6 +8,8 @@ namespace cru { + class Application; + namespace ui { class WindowClass; @@ -21,6 +23,30 @@ namespace cru class TimerManager; + + class GodWindow : public Object + { + public: + explicit GodWindow(Application* application); + GodWindow(const GodWindow& other) = delete; + GodWindow(GodWindow&& other) = delete; + GodWindow& operator=(const GodWindow& other) = delete; + GodWindow& operator=(GodWindow&& other) = delete; + ~GodWindow() override; + + HWND GetHandle() const + { + return hwnd_; + } + + std::optional<LRESULT> HandleGodWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param); + + private: + Application* application_; + std::unique_ptr<ui::WindowClass> god_window_class_; + HWND hwnd_; + }; + class Application : public Object { public: @@ -60,24 +86,19 @@ namespace cru return h_instance_; } - HWND GetGodWindowHandle() const + GodWindow* GetGodWindow() const { - return god_hwnd_; + return god_window_.get(); } private: - static LRESULT __stdcall GodWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); - std::optional<LRESULT> HandleGodWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param); - - private: HINSTANCE h_instance_; - std::unique_ptr<ui::WindowClass> god_window_class_; - HWND god_hwnd_; - std::unique_ptr<ui::WindowManager> window_manager_; std::unique_ptr<graph::GraphManager> graph_manager_; std::unique_ptr<TimerManager> timer_manager_; + + std::unique_ptr<GodWindow> god_window_; }; diff --git a/CruUI/timer.cpp b/CruUI/timer.cpp index 82a2a0f4..eabc7865 100644 --- a/CruUI/timer.cpp +++ b/CruUI/timer.cpp @@ -21,7 +21,7 @@ namespace cru UINT_PTR TimerManager::CreateTimer(const UINT microseconds, const bool loop, const TimerAction & action) { - auto id = ::SetTimer(Application::GetInstance()->GetGodWindowHandle(), 0, microseconds, nullptr); + auto id = ::SetTimer(Application::GetInstance()->GetGodWindow()->GetHandle(), 0, microseconds, nullptr); if (loop) map_[id] = action; else diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp index c528d3ca..132bd3e7 100644 --- a/CruUI/ui/controls/text_block.cpp +++ b/CruUI/ui/controls/text_block.cpp @@ -111,6 +111,7 @@ namespace cru { if (args.GetMouseButton() == MouseButton::Left) { + RequestFocus(); const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), true); if (hit_test_result.has_value()) { @@ -118,6 +119,10 @@ namespace cru is_selecting_ = true; GetWindow()->CaptureMouseFor(this); } + else + { + selected_range_ = std::nullopt; + } } Control::OnMouseDownCore(args); } @@ -126,13 +131,17 @@ namespace cru { if (is_selecting_) { + is_mouse_moved_ = true; const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), false).value(); if (hit_test_result > mouse_down_position_) selected_range_ = TextRange(mouse_down_position_, hit_test_result - mouse_down_position_); - else + else if (hit_test_result < mouse_down_position_) selected_range_ = TextRange(hit_test_result, mouse_down_position_ - hit_test_result); + else + selected_range_ = std::nullopt; Repaint(); } + Control::OnMouseMoveCore(args); } void TextBlock::OnMouseUpCore(events::MouseButtonEventArgs& args) @@ -141,10 +150,24 @@ namespace cru { if (is_selecting_) { + if (!is_mouse_moved_) + { + selected_range_ = std::nullopt; + Repaint(); + } + is_mouse_moved_ = false; is_selecting_ = false; GetWindow()->ReleaseCurrentMouseCapture(); } } + Control::OnMouseUpCore(args); + } + + void TextBlock::OnLoseFocusCore(events::UiEventArgs& args) + { + selected_range_ = std::nullopt; + Repaint(); + Control::OnLoseFocusCore(args); } Size TextBlock::OnMeasure(const Size& available_size) diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h index 1d1166a5..c817104e 100644 --- a/CruUI/ui/controls/text_block.h +++ b/CruUI/ui/controls/text_block.h @@ -104,6 +104,8 @@ namespace cru void OnMouseMoveCore(events::MouseEventArgs& args) override; void OnMouseUpCore(events::MouseButtonEventArgs& args) override; + void OnLoseFocusCore(events::UiEventArgs& args) override; + Size OnMeasure(const Size& available_size) override; private: @@ -124,6 +126,7 @@ namespace cru Vector<std::shared_ptr<TextLayoutHandler>> text_layout_handlers_; unsigned mouse_down_position_ = 0; + bool is_mouse_moved_ = false; std::optional<TextRange> selected_range_ = std::nullopt; bool is_selecting_ = false; |