aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-09-13 00:14:59 +0800
committercrupest <crupest@outlook.com>2018-09-13 00:14:59 +0800
commit5f35ba198582bb93e16d34c8d94ffdc8f453068d (patch)
tree9ac9865ff3f058d688240abff8b7a44c876dd32a
parentbbcd0257150d967bdccd3ab89c100d02bd7a23d3 (diff)
downloadcru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.tar.gz
cru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.tar.bz2
cru-5f35ba198582bb93e16d34c8d94ffdc8f453068d.zip
...
-rw-r--r--CruUI/application.cpp125
-rw-r--r--CruUI/application.h39
-rw-r--r--CruUI/timer.cpp2
-rw-r--r--CruUI/ui/controls/text_block.cpp25
-rw-r--r--CruUI/ui/controls/text_block.h3
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;