aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-04-04 17:12:25 +0800
committercrupest <crupest@outlook.com>2019-04-04 17:12:25 +0800
commita410e2048db6f5ef6fb50e401a59b4b98b979050 (patch)
tree500680c63b074e8c3eefd756fd6a1d0f41840c1a
parentfcaf471275a67d718887430ee63a53890915c4c7 (diff)
downloadcru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.gz
cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.bz2
cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.zip
...
-rw-r--r--drafts/input_util.cpp (renamed from src/ui/input_util.cpp)0
-rw-r--r--include/cru/common/ui_base.hpp16
-rw-r--r--include/cru/platform/painter.hpp5
-rw-r--r--include/cru/platform/text_layout.hpp10
-rw-r--r--include/cru/platform/win/win_painter.hpp5
-rw-r--r--include/cru/platform/win/win_pre_config.hpp1
-rw-r--r--include/cru/platform/win/win_text_layout.hpp2
-rw-r--r--include/cru/ui/content_control.hpp (renamed from src/ui/content_control.hpp)2
-rw-r--r--include/cru/ui/control.hpp (renamed from src/ui/control.hpp)65
-rw-r--r--include/cru/ui/layout_control.hpp (renamed from src/ui/layout_control.hpp)2
-rw-r--r--include/cru/ui/no_child_control.hpp (renamed from src/ui/no_child_control.hpp)2
-rw-r--r--include/cru/ui/render/text_render_object.hpp60
-rw-r--r--include/cru/ui/ui_manager.hpp (renamed from src/ui/ui_manager.hpp)36
-rw-r--r--include/cru/ui/window.hpp97
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/platform_win/win_font.cpp3
-rw-r--r--src/platform_win/win_painter.cpp31
-rw-r--r--src/platform_win/win_text_layout.cpp13
-rw-r--r--src/ui/content_control.cpp4
-rw-r--r--src/ui/control.cpp8
-rw-r--r--src/ui/input_util.hpp10
-rw-r--r--src/ui/layout_control.cpp7
-rw-r--r--src/ui/no_child_control.cpp2
-rw-r--r--src/ui/render/text_render_object.cpp151
-rw-r--r--src/ui/ui_manager.cpp77
-rw-r--r--src/ui/window.cpp283
-rw-r--r--src/ui/window.hpp162
-rw-r--r--src/util/math_util.hpp51
28 files changed, 342 insertions, 764 deletions
diff --git a/src/ui/input_util.cpp b/drafts/input_util.cpp
index 193cba4a..193cba4a 100644
--- a/src/ui/input_util.cpp
+++ b/drafts/input_util.cpp
diff --git a/include/cru/common/ui_base.hpp b/include/cru/common/ui_base.hpp
index 0da18f22..017e3bd1 100644
--- a/include/cru/common/ui_base.hpp
+++ b/include/cru/common/ui_base.hpp
@@ -233,9 +233,25 @@ struct TextRange final {
};
struct Color {
+ constexpr Color() : Color(0, 0, 0, 255) {}
+ constexpr Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue,
+ std::uint8_t alpha = 255)
+ : red(red), green(green), blue(blue), alpha(alpha) {}
+
+ constexpr static Color FromHex(std::uint32_t hex) {
+ return Color(hex & (0b11111111 << 16), hex & (0b11111111 << 8),
+ hex & (0b11111111), hex & (0b11111111 << 24));
+ }
+
std::uint8_t red;
std::uint8_t green;
std::uint8_t blue;
std::uint8_t alpha;
};
+
+namespace colors {
+constexpr Color black{0, 0, 0};
+constexpr Color white{255, 255, 255};
+constexpr Color skyblue = Color::FromHex(0x87ceeb);
+} // namespace colors
} // namespace cru::ui
diff --git a/include/cru/platform/painter.hpp b/include/cru/platform/painter.hpp
index 2e979184..7310bc5c 100644
--- a/include/cru/platform/painter.hpp
+++ b/include/cru/platform/painter.hpp
@@ -7,13 +7,18 @@
namespace cru::platform {
struct Brush;
struct Geometry;
+struct TextLayout;
struct Painter : virtual Interface {
virtual Matrix GetTransform() = 0;
virtual void SetTransform(const Matrix& matrix) = 0;
+ virtual void StrokeRectangle(const ui::Rect& rectangle, Brush* brush,
+ float width) = 0;
+ virtual void FillRectangle(const ui::Rect& rectangle, Brush* brush) = 0;
virtual void StrokeGeometry(Geometry* geometry, Brush* brush,
float width) = 0;
virtual void FillGeometry(Geometry* geometry, Brush* brush) = 0;
+ virtual void DrawText(const ui::Point& offset, TextLayout* text_layout, Brush* brush);
virtual void EndDraw() = 0;
virtual bool IsDisposed() = 0;
};
diff --git a/include/cru/platform/text_layout.hpp b/include/cru/platform/text_layout.hpp
index 7bcf01fe..e43adfde 100644
--- a/include/cru/platform/text_layout.hpp
+++ b/include/cru/platform/text_layout.hpp
@@ -3,16 +3,22 @@
#include "cru/common/ui_base.hpp"
-#include <vector>
+#include <memory>
#include <string>
+#include <vector>
namespace cru::platform {
+struct FontDescriptor;
+
struct TextLayout : virtual Interface {
virtual std::wstring GetText() = 0;
virtual void SetText(std::wstring new_text) = 0;
+ virtual std::shared_ptr<FontDescriptor> GetFont() = 0;
+ virtual void SetFont(std::shared_ptr<FontDescriptor> font) = 0;
virtual void SetMaxWidth(float max_width) = 0;
virtual void SetMaxHeight(float max_height) = 0;
virtual ui::Rect GetTextBounds() = 0;
- virtual std::vector<ui::Rect> TextRangeRect(const ui::TextRange& text_range) = 0;
+ virtual std::vector<ui::Rect> TextRangeRect(
+ const ui::TextRange& text_range) = 0;
};
} // namespace cru::platform
diff --git a/include/cru/platform/win/win_painter.hpp b/include/cru/platform/win/win_painter.hpp
index 1e449d85..dfb981d5 100644
--- a/include/cru/platform/win/win_painter.hpp
+++ b/include/cru/platform/win/win_painter.hpp
@@ -17,8 +17,13 @@ class WinPainter : public Object, public virtual Painter {
Matrix GetTransform() override;
void SetTransform(const Matrix& matrix) override;
+ void StrokeRectangle(const ui::Rect& rectangle, Brush* brush,
+ float width) override;
+ void FillRectangle(const ui::Rect& rectangle, Brush* brush) override;
void StrokeGeometry(Geometry* geometry, Brush* brush, float width) override;
void FillGeometry(Geometry* geometry, Brush* brush) override;
+ void DrawText(const ui::Point& offset, TextLayout* text_layout,
+ Brush* brush) override;
void EndDraw() override;
bool IsDisposed() override { return is_disposed; }
diff --git a/include/cru/platform/win/win_pre_config.hpp b/include/cru/platform/win/win_pre_config.hpp
index d6ba4ec7..6962eb7b 100644
--- a/include/cru/platform/win/win_pre_config.hpp
+++ b/include/cru/platform/win/win_pre_config.hpp
@@ -4,6 +4,7 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#undef CreateWindow
+#undef DrawText
#include <d2d1_2.h>
#include <d3d11.h>
diff --git a/include/cru/platform/win/win_text_layout.hpp b/include/cru/platform/win/win_text_layout.hpp
index 277bbcae..9c93aa8c 100644
--- a/include/cru/platform/win/win_text_layout.hpp
+++ b/include/cru/platform/win/win_text_layout.hpp
@@ -21,6 +21,8 @@ class WinTextLayout : public Object, public virtual TextLayout {
std::wstring GetText() override;
void SetText(std::wstring new_text) override;
+ std::shared_ptr<FontDescriptor> GetFont();
+ void SetFont(std::shared_ptr<FontDescriptor> font);
void SetMaxWidth(float max_width) override;
void SetMaxHeight(float max_height) override;
ui::Rect GetTextBounds() override;
diff --git a/src/ui/content_control.hpp b/include/cru/ui/content_control.hpp
index 88e7f60f..f88ec157 100644
--- a/src/ui/content_control.hpp
+++ b/include/cru/ui/content_control.hpp
@@ -1,6 +1,4 @@
#pragma once
-#include "pre.hpp"
-
#include "control.hpp"
namespace cru::ui {
diff --git a/src/ui/control.hpp b/include/cru/ui/control.hpp
index b69734d6..684af2f0 100644
--- a/src/ui/control.hpp
+++ b/include/cru/ui/control.hpp
@@ -1,14 +1,17 @@
#pragma once
#include "cru/common/base.hpp"
-#include "cru/ui/event/ui_event.hpp"
-
-#include ""
+#include "cru/platform/basic_types.hpp"
+#include "event/ui_event.hpp"
#include <string_view>
+#include <vector>
namespace cru::ui {
class Window;
+namespace render {
+class RenderObject;
+} // namespace render
class Control : public Object {
friend class Window;
@@ -57,64 +60,64 @@ class Control : public Object {
//*************** region: events ***************
public:
// Raised when mouse enter the control.
- events::RoutedEvent<events::MouseEventArgs>* MouseEnterEvent() {
+ event::RoutedEvent<event::MouseEventArgs>* MouseEnterEvent() {
return &mouse_enter_event_;
}
// Raised when mouse is leave the control.
- events::RoutedEvent<events::MouseEventArgs>* MouseLeaveEvent() {
+ event::RoutedEvent<event::MouseEventArgs>* MouseLeaveEvent() {
return &mouse_leave_event_;
}
// Raised when mouse is move in the control.
- events::RoutedEvent<events::MouseEventArgs>* MouseMoveEvent() {
+ event::RoutedEvent<event::MouseEventArgs>* MouseMoveEvent() {
return &mouse_move_event_;
}
// Raised when a mouse button is pressed in the control.
- events::RoutedEvent<events::MouseButtonEventArgs>* MouseDownEvent() {
+ event::RoutedEvent<event::MouseButtonEventArgs>* MouseDownEvent() {
return &mouse_down_event_;
}
// Raised when a mouse button is released in the control.
- events::RoutedEvent<events::MouseButtonEventArgs>* MouseUpEvent() {
+ event::RoutedEvent<event::MouseButtonEventArgs>* MouseUpEvent() {
return &mouse_up_event_;
}
// Raised when a mouse button is pressed in the control and released in the
// control with mouse not leaving it between two operations.
- events::RoutedEvent<events::MouseButtonEventArgs>* MouseClickEvent() {
+ event::RoutedEvent<event::MouseButtonEventArgs>* MouseClickEvent() {
return &mouse_click_event_;
}
- events::RoutedEvent<events::MouseWheelEventArgs>* MouseWheelEvent() {
+ event::RoutedEvent<event::MouseWheelEventArgs>* MouseWheelEvent() {
return &mouse_wheel_event_;
}
- events::RoutedEvent<events::KeyEventArgs>* KeyDownEvent() {
+ event::RoutedEvent<event::KeyEventArgs>* KeyDownEvent() {
return &key_down_event_;
}
- events::RoutedEvent<events::KeyEventArgs>* KeyUpEvent() {
+ event::RoutedEvent<event::KeyEventArgs>* KeyUpEvent() {
return &key_up_event_;
}
- events::RoutedEvent<events::CharEventArgs>* CharEvent() {
- return &char_event_;
- }
- events::RoutedEvent<events::FocusChangeEventArgs>* GainFocusEvent() {
+ // event::RoutedEvent<event::CharEventArgs>* CharEvent() {
+ // return &char_event_;
+ // }
+ event::RoutedEvent<event::FocusChangeEventArgs>* GainFocusEvent() {
return &gain_focus_event_;
}
- events::RoutedEvent<events::FocusChangeEventArgs>* LoseFocusEvent() {
+ event::RoutedEvent<event::FocusChangeEventArgs>* LoseFocusEvent() {
return &lose_focus_event_;
}
private:
- events::RoutedEvent<events::MouseEventArgs> mouse_enter_event_;
- events::RoutedEvent<events::MouseEventArgs> mouse_leave_event_;
- events::RoutedEvent<events::MouseEventArgs> mouse_move_event_;
- events::RoutedEvent<events::MouseButtonEventArgs> mouse_down_event_;
- events::RoutedEvent<events::MouseButtonEventArgs> mouse_up_event_;
- events::RoutedEvent<events::MouseButtonEventArgs> mouse_click_event_;
- events::RoutedEvent<events::MouseWheelEventArgs> mouse_wheel_event_;
+ event::RoutedEvent<event::MouseEventArgs> mouse_enter_event_;
+ event::RoutedEvent<event::MouseEventArgs> mouse_leave_event_;
+ event::RoutedEvent<event::MouseEventArgs> mouse_move_event_;
+ event::RoutedEvent<event::MouseButtonEventArgs> mouse_down_event_;
+ event::RoutedEvent<event::MouseButtonEventArgs> mouse_up_event_;
+ event::RoutedEvent<event::MouseButtonEventArgs> mouse_click_event_;
+ event::RoutedEvent<event::MouseWheelEventArgs> mouse_wheel_event_;
- events::RoutedEvent<events::KeyEventArgs> key_down_event_;
- events::RoutedEvent<events::KeyEventArgs> key_up_event_;
- events::RoutedEvent<events::CharEventArgs> char_event_;
+ event::RoutedEvent<event::KeyEventArgs> key_down_event_;
+ event::RoutedEvent<event::KeyEventArgs> key_up_event_;
+ // event::RoutedEvent<event::CharEventArgs> char_event_;
- events::RoutedEvent<events::FocusChangeEventArgs> gain_focus_event_;
- events::RoutedEvent<events::FocusChangeEventArgs> lose_focus_event_;
+ event::RoutedEvent<event::FocusChangeEventArgs> gain_focus_event_;
+ event::RoutedEvent<event::FocusChangeEventArgs> lose_focus_event_;
//*************** region: tree ***************
protected:
@@ -124,8 +127,8 @@ class Control : public Object {
//*************** region: additional mouse event ***************
protected:
- virtual void OnMouseClickBegin(MouseButton button);
- virtual void OnMouseClickEnd(MouseButton button);
+ virtual void OnMouseClickBegin(platform::MouseButton button);
+ virtual void OnMouseClickEnd(platform::MouseButton button);
private:
Window* window_ = nullptr;
diff --git a/src/ui/layout_control.hpp b/include/cru/ui/layout_control.hpp
index 53f53186..187f0e0d 100644
--- a/src/ui/layout_control.hpp
+++ b/include/cru/ui/layout_control.hpp
@@ -1,6 +1,4 @@
#pragma once
-#include "pre.hpp"
-
#include "control.hpp"
namespace cru::ui {
diff --git a/src/ui/no_child_control.hpp b/include/cru/ui/no_child_control.hpp
index 26b5546f..62a9fa8d 100644
--- a/src/ui/no_child_control.hpp
+++ b/include/cru/ui/no_child_control.hpp
@@ -1,6 +1,4 @@
#pragma once
-#include "pre.hpp"
-
#include "control.hpp"
namespace cru::ui {
diff --git a/include/cru/ui/render/text_render_object.hpp b/include/cru/ui/render/text_render_object.hpp
index 7827f994..329af18a 100644
--- a/include/cru/ui/render/text_render_object.hpp
+++ b/include/cru/ui/render/text_render_object.hpp
@@ -1,35 +1,38 @@
#pragma once
-#include "pre.hpp"
-
#include "render_object.hpp"
+#include <memory>
+#include <string>
+
// forward declarations
-struct ID2D1Brush;
-struct IDWriteTextFormat;
-struct IDWriteTextLayout;
+namespace cru::platform {
+struct Brush;
+struct FontDescriptor;
+struct TextLayout;
+} // namespace cru::platform
namespace cru::ui::render {
class TextRenderObject : public RenderObject {
public:
- TextRenderObject(ID2D1Brush* brush, IDWriteTextFormat* format,
- ID2D1Brush* selection_brush);
+ TextRenderObject(std::shared_ptr<platform::Brush> brush,
+ std::shared_ptr<platform::FontDescriptor> font,
+ std::shared_ptr<platform::Brush> selection_brush);
TextRenderObject(const TextRenderObject& other) = delete;
TextRenderObject(TextRenderObject&& other) = delete;
TextRenderObject& operator=(const TextRenderObject& other) = delete;
TextRenderObject& operator=(TextRenderObject&& other) = delete;
~TextRenderObject() override;
- String GetText() const { return text_; }
- void SetText(String new_text) {
- text_ = std::move(new_text);
- RecreateTextLayout();
- }
+ std::wstring GetText() const;
+ void SetText(std::wstring new_text);
- ID2D1Brush* GetBrush() const { return brush_; }
- void SetBrush(ID2D1Brush* new_brush);
+ std::shared_ptr<platform::Brush> GetBrush() const { return brush_; }
+ void SetBrush(std::shared_ptr<platform::Brush> new_brush) {
+ new_brush.swap(brush_);
+ }
- IDWriteTextFormat* GetTextFormat() const { return text_format_; }
- void SetTextFormat(IDWriteTextFormat* new_text_format);
+ std::shared_ptr<platform::FontDescriptor> GetFont() const;
+ void SetFont(std::shared_ptr<platform::FontDescriptor> font);
std::optional<TextRange> GetSelectionRange() const {
return selection_range_;
@@ -38,12 +41,14 @@ class TextRenderObject : public RenderObject {
selection_range_ = std::move(new_range);
}
- ID2D1Brush* GetSelectionBrush() const { return selection_brush_; }
- void SetSelectionBrush(ID2D1Brush* new_brush);
-
- void Refresh() { RecreateTextLayout(); }
+ std::shared_ptr<platform::Brush> GetSelectionBrush() const {
+ return selection_brush_;
+ }
+ void SetSelectionBrush(std::shared_ptr<platform::Brush> new_brush) {
+ new_brush.swap(selection_brush_);
+ }
- void Draw(ID2D1RenderTarget* render_target) override;
+ void Draw(platform::Painter* painter) override;
RenderObject* HitTest(const Point& point) override;
@@ -54,16 +59,11 @@ class TextRenderObject : public RenderObject {
void OnLayoutContent(const Rect& content_rect) override;
private:
- void RecreateTextLayout();
-
- private:
- String text_;
-
- ID2D1Brush* brush_ = nullptr;
- IDWriteTextFormat* text_format_ = nullptr;
- IDWriteTextLayout* text_layout_ = nullptr;
+ std::shared_ptr<platform::Brush> brush_;
+ std::shared_ptr<platform::FontDescriptor> font_;
+ std::shared_ptr<platform::TextLayout> text_layout_;
std::optional<TextRange> selection_range_ = std::nullopt;
- ID2D1Brush* selection_brush_ = nullptr;
+ std::shared_ptr<platform::Brush> selection_brush_;
};
} // namespace cru::ui::render
diff --git a/src/ui/ui_manager.hpp b/include/cru/ui/ui_manager.hpp
index 107b536c..6f4a3bc0 100644
--- a/src/ui/ui_manager.hpp
+++ b/include/cru/ui/ui_manager.hpp
@@ -1,20 +1,14 @@
#pragma once
-#include "pre.hpp"
+#include "cru/common/base.hpp"
-#include "base.hpp"
+#include <memory>
-struct ID2D1Brush;
-struct IDWriteTextFormat;
-namespace cru::graph {
-class GraphManager;
-}
+namespace cru::platform {
+struct Brush;
+struct FontDescriptor;
+} // namespace cru::platform
namespace cru::ui {
-struct CaretInfo {
- std::chrono::milliseconds caret_blink_duration;
- float half_caret_width;
-};
-
class PredefineResources : public Object {
public:
PredefineResources();
@@ -22,15 +16,15 @@ class PredefineResources : public Object {
PredefineResources(PredefineResources&& other) = delete;
PredefineResources& operator=(const PredefineResources& other) = delete;
PredefineResources& operator=(PredefineResources&& other) = delete;
- ~PredefineResources() override;
+ ~PredefineResources() override = default;
// region Button
- ID2D1Brush* button_normal_border_brush = nullptr;
+ std::shared_ptr<platform::Brush> button_normal_border_brush;
// region TextBlock
- ID2D1Brush* text_block_selection_brush = nullptr;
- ID2D1Brush* text_block_text_brush = nullptr;
- IDWriteTextFormat* text_block_text_format = nullptr;
+ std::shared_ptr<platform::Brush> text_block_selection_brush;
+ std::shared_ptr<platform::Brush> text_block_text_brush;
+ std::shared_ptr<platform::FontDescriptor> text_block_font;
};
class UiManager : public Object {
@@ -47,15 +41,11 @@ class UiManager : public Object {
UiManager& operator=(UiManager&& other) = delete;
~UiManager() override = default;
- CaretInfo GetCaretInfo() const { return caret_info_; }
-
const PredefineResources* GetPredefineResources() const {
- return &predefine_resources_;
+ return predefine_resources_.get();
}
private:
- CaretInfo caret_info_;
-
- PredefineResources predefine_resources_;
+ std::unique_ptr<PredefineResources> predefine_resources_;
};
} // namespace cru::ui
diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp
new file mode 100644
index 00000000..043aae35
--- /dev/null
+++ b/include/cru/ui/window.hpp
@@ -0,0 +1,97 @@
+#pragma once
+#include "content_control.hpp"
+
+#include "event/ui_event.hpp"
+
+#include <memory>
+
+namespace cru::platform {
+struct NativeWindow;
+}
+
+namespace cru::ui {
+namespace render {
+class WindowRenderObject;
+}
+
+class Window final : public ContentControl {
+ public:
+ static constexpr auto control_type = L"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::wstring_view GetControlType() const override final;
+
+ render::RenderObject* GetRenderObject() const override;
+
+ platform::NativeWindow* GetNativeWindow() const;
+
+ Control* GetMouseHoverControl() const { return mouse_hover_control_; }
+
+ //*************** region: focus ***************
+
+ // Request focus for specified control.
+ bool RequestFocusFor(Control* control);
+
+ // Get the control that has focus.
+ Control* GetFocusControl();
+
+ protected:
+ void OnChildChanged(Control* old_child, Control* new_child) override;
+
+ private:
+ Control* HitTest(const Point& point);
+
+ //*************** region: native messages ***************
+
+ void OnNativeDestroy();
+ void OnNativePaint();
+ void OnNativeResize(float new_width, float new_height);
+
+ void OnSetFocusInternal();
+ void OnKillFocusInternal();
+
+ void OnMouseMoveInternal(POINT point);
+ void OnMouseLeaveInternal();
+ void OnMouseDownInternal(MouseButton button, POINT point);
+ void OnMouseUpInternal(MouseButton button, POINT point);
+
+ void OnMouseWheelInternal(short delta, POINT point);
+ void OnKeyDownInternal(int virtual_code);
+ void OnKeyUpInternal(int virtual_code);
+ void OnCharInternal(wchar_t c);
+
+ void OnActivatedInternal();
+ void OnDeactivatedInternal();
+
+ //*************** region: event dispatcher helper ***************
+
+ void DispatchMouseHoverControlChangeEvent(Control* old_control,
+ Control* new_control,
+ const Point& point);
+
+ private:
+ platform::NativeWindow* native_window_;
+ std::vector<EventHandlerToken> revoke_tokens_;
+
+ std::shared_ptr<render::WindowRenderObject> render_object_;
+
+ Control* mouse_hover_control_ = nullptr;
+
+ Control* focus_control_ = this; // "focus_control_" can't be nullptr
+};
+} // namespace cru::ui
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8041d8cc..4155e800 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,6 @@
add_library(cru_ui STATIC
ui/content_control.cpp
ui/control.cpp
- ui/input_util.cpp
ui/layout_control.cpp
ui/no_child_control.cpp
ui/ui_manager.cpp
diff --git a/src/platform_win/win_font.cpp b/src/platform_win/win_font.cpp
index e0a309cc..bca70b9f 100644
--- a/src/platform_win/win_font.cpp
+++ b/src/platform_win/win_font.cpp
@@ -18,5 +18,8 @@ WinFontDescriptor::WinFontDescriptor(GraphManager* graph_manager,
font_family.data(), nullptr, DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, font_size,
buffer.data(), &text_format_));
+
+ ThrowIfFailed(text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
+ ThrowIfFailed(text_format_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
}
} // namespace cru::platform::win
diff --git a/src/platform_win/win_painter.cpp b/src/platform_win/win_painter.cpp
index 748d5766..b648f97d 100644
--- a/src/platform_win/win_painter.cpp
+++ b/src/platform_win/win_painter.cpp
@@ -6,6 +6,7 @@
#include "cru/platform/win/win_brush.hpp"
#include "cru/platform/win/win_geometry.hpp"
#include "cru/platform/win/win_native_window.hpp"
+#include "cru/platform/win/win_text_layout.hpp"
#include "cru/platform/win/window_render_target.hpp"
#include <cassert>
@@ -28,15 +29,33 @@ WinPainter::~WinPainter() {
}
Matrix WinPainter::GetTransform() {
+ assert(!IsDisposed());
D2D1_MATRIX_3X2_F m;
render_target_->GetTransform(&m);
return util::Convert(m);
}
void WinPainter::SetTransform(const Matrix& matrix) {
+ assert(!IsDisposed());
render_target_->SetTransform(util::Convert(matrix));
}
+void WinPainter::StrokeRectangle(const ui::Rect& rectangle, Brush* brush,
+ float width) {
+ assert(!IsDisposed());
+ const auto b = dynamic_cast<WinBrush*>(brush);
+ assert(b);
+ render_target_->DrawRectangle(util::Convert(rectangle), b->GetD2DBrush(),
+ width);
+}
+
+void WinPainter::FillRectangle(const ui::Rect& rectangle, Brush* brush) {
+ assert(!IsDisposed());
+ const auto b = dynamic_cast<WinBrush*>(brush);
+ assert(b);
+ render_target_->FillRectangle(util::Convert(rectangle), b->GetD2DBrush());
+}
+
void WinPainter::StrokeGeometry(Geometry* geometry, Brush* brush, float width) {
assert(!IsDisposed());
const auto g = dynamic_cast<WinGeometry*>(geometry);
@@ -57,6 +76,18 @@ void WinPainter::FillGeometry(Geometry* geometry, Brush* brush) {
render_target_->FillGeometry(g->GetNative(), b->GetD2DBrush());
}
+void WinPainter::DrawText(const ui::Point& offset, TextLayout* text_layout,
+ Brush* brush) {
+ assert(!IsDisposed());
+ const auto t = dynamic_cast<WinTextLayout*>(text_layout);
+ assert(t);
+ const auto b = dynamic_cast<WinBrush*>(brush);
+ assert(b);
+
+ render_target_->DrawTextLayout(util::Convert(offset),
+ t->GetDWriteTextLayout(), b->GetD2DBrush());
+}
+
void WinPainter::EndDraw() {
if (!IsDisposed()) {
ThrowIfFailed(render_target_->EndDraw());
diff --git a/src/platform_win/win_text_layout.cpp b/src/platform_win/win_text_layout.cpp
index 9915b56c..7ae87a80 100644
--- a/src/platform_win/win_text_layout.cpp
+++ b/src/platform_win/win_text_layout.cpp
@@ -30,6 +30,19 @@ void WinTextLayout::SetText(std::wstring new_text) {
max_width_, max_height_, &text_layout_));
}
+std::shared_ptr<FontDescriptor> WinTextLayout::GetFont() {
+ return font_descriptor_;
+}
+
+void WinTextLayout::SetFont(std::shared_ptr<FontDescriptor> font) {
+ auto f = std::dynamic_pointer_cast<WinFontDescriptor>(font);
+ assert(f);
+ f.swap(font_descriptor_);
+ ThrowIfFailed(graph_manager_->GetDWriteFactory()->CreateTextLayout(
+ text_.c_str(), text_.size(), font_descriptor_->GetDWriteTextFormat(),
+ max_width_, max_height_, &text_layout_));
+}
+
void WinTextLayout::SetMaxWidth(float max_width) {
max_width_ = max_width;
ThrowIfFailed(text_layout_->SetMaxWidth(max_width_));
diff --git a/src/ui/content_control.cpp b/src/ui/content_control.cpp
index d5abca1c..3a23164c 100644
--- a/src/ui/content_control.cpp
+++ b/src/ui/content_control.cpp
@@ -1,7 +1,9 @@
-#include "content_control.hpp"
+#include "cru/ui/content_control.hpp"
#include "window.hpp"
+#include <cassert>
+
namespace cru::ui {
ContentControl::ContentControl()
: child_vector_{nullptr}, child_(child_vector_[0]) {}
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 318d591a..c5d02d40 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -1,7 +1,9 @@
-#include "control.hpp"
+#include "cru/ui/control.hpp"
#include "window.hpp"
+#include <cassert>
+
namespace cru::ui {
void Control::_SetParent(Control* parent) {
const auto old_parent = GetParent();
@@ -61,7 +63,7 @@ void Control::OnAttachToWindow(Window* window) {}
void Control::OnDetachToWindow(Window* window) {}
-void Control::OnMouseClickBegin(MouseButton button) {}
+void Control::OnMouseClickBegin(platform::MouseButton button) {}
-void Control::OnMouseClickEnd(MouseButton button) {}
+void Control::OnMouseClickEnd(platform::MouseButton button) {}
} // namespace cru::ui
diff --git a/src/ui/input_util.hpp b/src/ui/input_util.hpp
deleted file mode 100644
index 2d01f725..00000000
--- a/src/ui/input_util.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include "pre.hpp"
-
-namespace cru::ui {
-enum class MouseButton { Left, Right, Middle };
-
-bool IsKeyDown(int virtual_code);
-bool IsKeyToggled(int virtual_code);
-bool IsAnyMouseButtonDown();
-} // namespace cru::ui
diff --git a/src/ui/layout_control.cpp b/src/ui/layout_control.cpp
index c0c4a7fe..9d789670 100644
--- a/src/ui/layout_control.cpp
+++ b/src/ui/layout_control.cpp
@@ -1,7 +1,9 @@
-#include "layout_control.hpp"
+#include "cru/ui/layout_control.hpp"
#include "window.hpp"
+#include <cassert>
+
namespace cru::ui {
LayoutControl::~LayoutControl() {
for (const auto child : children_) delete child;
@@ -10,7 +12,8 @@ LayoutControl::~LayoutControl() {
void LayoutControl::AddChild(Control* control, const int position) {
assert(control->GetParent() == nullptr); // The control already has a parent.
assert(!dynamic_cast<Window*>(control)); // Can't add a window as child.
- assert(position >= 0 || position <= this->children_.size()); // The position is out of range.
+ assert(position >= 0 ||
+ position <= this->children_.size()); // The position is out of range.
children_.insert(this->children_.cbegin() + position, control);
diff --git a/src/ui/no_child_control.cpp b/src/ui/no_child_control.cpp
index e6bbe813..81299411 100644
--- a/src/ui/no_child_control.cpp
+++ b/src/ui/no_child_control.cpp
@@ -1,4 +1,4 @@
-#include "no_child_control.hpp"
+#include "cru/ui/no_child_control.hpp"
namespace cru::ui {
const std::vector<Control*> NoChildControl::empty_control_vector{};
diff --git a/src/ui/render/text_render_object.cpp b/src/ui/render/text_render_object.cpp
index 69563ad7..bdf48c9a 100644
--- a/src/ui/render/text_render_object.cpp
+++ b/src/ui/render/text_render_object.cpp
@@ -1,103 +1,61 @@
-#include "text_render_object.hpp"
+#include "cru/ui/render/text_render_object.hpp"
-#include <d2d1.h>
-#include <dwrite.h>
-#include <algorithm>
+#include "cru/platform/graph_factory.hpp"
+#include "cru/platform/painter_util.hpp"
+#include "cru/platform/text_layout.hpp"
+#include "cru/platform/ui_applicaition.hpp"
-#include "exception.hpp"
-#include "graph/graph_manager.hpp"
-#include "graph/graph_util.hpp"
-#include "util/com_util.hpp"
+#include <algorithm>
+#include <cassert>
namespace cru::ui::render {
-TextRenderObject::TextRenderObject(ID2D1Brush* brush, IDWriteTextFormat* format,
- ID2D1Brush* selection_brush) {
+TextRenderObject::TextRenderObject(
+ std::shared_ptr<platform::Brush> brush,
+ std::shared_ptr<platform::FontDescriptor> font,
+ std::shared_ptr<platform::Brush> selection_brush) {
assert(brush);
- assert(format);
+ assert(font);
assert(selection_brush);
- brush->AddRef();
- format->AddRef();
- selection_brush->AddRef();
- this->brush_ = brush;
- this->text_format_ = format;
- this->selection_brush_ = selection_brush;
- try {
- RecreateTextLayout();
- } catch (...) {
- brush->Release();
- format->Release();
- selection_brush->Release();
- throw;
- }
-}
-TextRenderObject::~TextRenderObject() {
- util::SafeRelease(brush_);
- util::SafeRelease(text_format_);
- util::SafeRelease(text_layout_);
- util::SafeRelease(selection_brush_);
-}
+ brush.swap(brush_);
+ font.swap(font_);
+ selection_brush.swap(selection_brush_);
-void TextRenderObject::SetBrush(ID2D1Brush* new_brush) {
- assert(new_brush);
- util::SafeRelease(brush_);
- new_brush->AddRef();
- brush_ = new_brush;
-}
+ const auto graph_factory =
+ platform::UiApplication::GetInstance()->GetGraphFactory();
-void TextRenderObject::SetTextFormat(IDWriteTextFormat* new_text_format) {
- assert(new_text_format);
- util::SafeRelease(text_format_);
- new_text_format->AddRef();
- text_format_ = new_text_format;
- RecreateTextLayout();
+ text_layout_.reset(graph_factory->CreateTextLayout(font_, L""));
}
-void TextRenderObject::SetSelectionBrush(ID2D1Brush* new_brush) {
- assert(new_brush);
- util::SafeRelease(selection_brush_);
- new_brush->AddRef();
- selection_brush_ = new_brush;
+std::wstring TextRenderObject::GetText() const {
+ return text_layout_->GetText();
}
-namespace {
-void DrawSelectionRect(ID2D1RenderTarget* render_target,
- IDWriteTextLayout* layout, ID2D1Brush* brush,
- const std::optional<TextRange> range) {
- if (range.has_value()) {
- DWRITE_TEXT_METRICS text_metrics{};
- ThrowIfFailed(layout->GetMetrics(&text_metrics));
- const auto metrics_count =
- text_metrics.lineCount * text_metrics.maxBidiReorderingDepth;
-
- std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count);
- UINT32 actual_count;
- layout->HitTestTextRange(range.value().position, range.value().count, 0, 0,
- hit_test_metrics.data(), metrics_count,
- &actual_count);
+void TextRenderObject::SetText(std::wstring new_text) {
+ text_layout_->SetText(std::move(new_text));
+}
- hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count,
- hit_test_metrics.cend());
+std::shared_ptr<platform::FontDescriptor> TextRenderObject::GetFont() const {
+ return text_layout_->GetFont();
+}
- for (const auto& metrics : hit_test_metrics)
- render_target->FillRoundedRectangle(
- D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top,
- metrics.left + metrics.width,
- metrics.top + metrics.height),
- 3, 3),
- brush);
- }
+void TextRenderObject::SetFont(std::shared_ptr<platform::FontDescriptor> font) {
+ text_layout_->SetFont(std::move(font));
}
-} // namespace
-void TextRenderObject::Draw(ID2D1RenderTarget* render_target) {
- graph::WithTransform(
- render_target,
- D2D1::Matrix3x2F::Translation(GetMargin().left + GetPadding().left,
+void TextRenderObject::Draw(platform::Painter* painter) {
+ platform::util::WithTransform(
+ painter,
+ platform::Matrix::Translation(GetMargin().left + GetPadding().left,
GetMargin().top + GetPadding().top),
- [this](auto rt) {
- DrawSelectionRect(rt, text_layout_, selection_brush_, selection_range_);
- rt->DrawTextLayout(D2D1::Point2F(), text_layout_, brush_);
+ [this](platform::Painter* p) {
+ if (this->selection_range_.has_value()) {
+ const auto&& rects =
+ text_layout_->TextRangeRect(this->selection_range_.value());
+ for (const auto& rect : rects)
+ p->FillRectangle(rect, this->GetSelectionBrush().get());
+ }
+ p->DrawText(Point{}, text_layout_.get(), brush_.get());
});
}
@@ -115,34 +73,15 @@ RenderObject* TextRenderObject::HitTest(const Point& point) {
void TextRenderObject::OnSizeChanged(const Size& old_size,
const Size& new_size) {
const auto&& size = GetContentRect().GetSize();
- ThrowIfFailed(text_layout_->SetMaxWidth(size.width));
- ThrowIfFailed(text_layout_->SetMaxHeight(size.height));
+ text_layout_->SetMaxWidth(size.width);
+ text_layout_->SetMaxHeight(size.height);
}
Size TextRenderObject::OnMeasureContent(const Size& available_size) {
- ThrowIfFailed(text_layout_->SetMaxWidth(available_size.width));
- ThrowIfFailed(text_layout_->SetMaxHeight(available_size.height));
-
- DWRITE_TEXT_METRICS metrics;
- ThrowIfFailed(text_layout_->GetMetrics(&metrics));
-
- return Size(metrics.width, metrics.height);
+ text_layout_->SetMaxWidth(available_size.width);
+ text_layout_->SetMaxHeight(available_size.height);
+ return text_layout_->GetTextBounds().GetSize();
}
void TextRenderObject::OnLayoutContent(const Rect& content_rect) {}
-
-void TextRenderObject::RecreateTextLayout() {
- assert(text_format_ != nullptr);
-
- util::SafeRelease(text_layout_);
-
- const auto dwrite_factory =
- graph::GraphManager::GetInstance()->GetDWriteFactory();
-
- const auto&& size = GetContentRect().GetSize();
-
- ThrowIfFailed(dwrite_factory->CreateTextLayout(
- text_.c_str(), static_cast<UINT32>(text_.size()), text_format_,
- size.width, size.height, &text_layout_));
-}
} // namespace cru::ui::render
diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp
index 4d14575b..9c3c00d2 100644
--- a/src/ui/ui_manager.cpp
+++ b/src/ui/ui_manager.cpp
@@ -1,74 +1,27 @@
-#include "ui_manager.hpp"
+#include "cru/ui/ui_manager.hpp"
-#include <Windows.h>
-#include <d2d1.h>
-#include <dwrite.h>
-
-#include "application.hpp"
-#include "exception.hpp"
-#include "graph/graph_manager.hpp"
-#include "graph/graph_util.hpp"
-#include "util/com_util.hpp"
+#include "cru/platform/graph_factory.hpp"
+#include "cru/platform/ui_applicaition.hpp"
namespace cru::ui {
-namespace {
-void GetSystemCaretInfo(CaretInfo* caret_info) {
- caret_info->caret_blink_duration =
- std::chrono::milliseconds(::GetCaretBlinkTime());
- DWORD caret_width;
- if (!::SystemParametersInfoW(SPI_GETCARETWIDTH, 0, &caret_width, 0))
- throw Win32Error(::GetLastError(), "Failed to get system caret width.");
- caret_info->half_caret_width = caret_width / 2.0f;
-}
-
-IDWriteTextFormat* CreateDefaultTextFormat() {
- const auto dwrite_factory =
- graph::GraphManager::GetInstance()->GetDWriteFactory();
- IDWriteTextFormat* text_format;
-
- ThrowIfFailed(dwrite_factory->CreateTextFormat(
- L"等线", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
- DWRITE_FONT_STRETCH_NORMAL, 24.0, L"zh-cn", &text_format));
-
- ThrowIfFailed(text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
- ThrowIfFailed(
- text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
-
- return text_format;
-}
-} // namespace
-
PredefineResources::PredefineResources() {
- try {
- button_normal_border_brush =
- graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black));
+ const auto graph_factory =
+ platform::UiApplication::GetInstance()->GetGraphFactory();
- text_block_selection_brush =
- graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue));
- text_block_text_brush =
- graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black));
- text_block_text_format = CreateDefaultTextFormat();
- } catch (...) {
- util::SafeRelease(button_normal_border_brush);
- util::SafeRelease(text_block_selection_brush);
- util::SafeRelease(text_block_text_brush);
- util::SafeRelease(text_block_text_format);
- }
-}
+ button_normal_border_brush.reset(
+ graph_factory->CreateSolidColorBrush(colors::black));
-PredefineResources::~PredefineResources() {
- util::SafeRelease(button_normal_border_brush);
- util::SafeRelease(text_block_selection_brush);
- util::SafeRelease(text_block_text_brush);
- util::SafeRelease(text_block_text_format);
+ text_block_selection_brush.reset(
+ graph_factory->CreateSolidColorBrush(colors::skyblue));
+ text_block_text_brush.reset(
+ graph_factory->CreateSolidColorBrush(colors::black));
+ text_block_font.reset(graph_factory->CreateFontDescriptor(L"等线", 24.0f));
}
UiManager* UiManager::GetInstance() {
- return Application::GetInstance()->ResolveSingleton<UiManager>(
- [](auto) { return new UiManager{}; });
+ static UiManager instance;
+ return &instance;
}
-UiManager::UiManager() : predefine_resources_() {
- GetSystemCaretInfo(&caret_info_);
-}
+UiManager::UiManager() : predefine_resources_(new PredefineResources()) {}
} // namespace cru::ui
diff --git a/src/ui/window.cpp b/src/ui/window.cpp
index d138424f..1065a3fb 100644
--- a/src/ui/window.cpp
+++ b/src/ui/window.cpp
@@ -1,14 +1,10 @@
-#include "window.hpp"
+#include "cru/ui/window.hpp"
-#include <d2d1_1.h>
-#include <windowsx.h>
+#include "cru/ui/render/window_render_object.hpp"
+#include "cru/platform/ui_applicaition.hpp"
+#include "cru/platform/native_window.hpp"
-#include "application.hpp"
-#include "exception.hpp"
-#include "graph/graph_manager.hpp"
-#include "graph/graph_util.hpp"
-#include "graph/window_render_target.hpp"
-#include "render/window_render_object.hpp"
+#include <cassert>
namespace cru::ui {
namespace {
@@ -27,7 +23,7 @@ namespace {
// as the rest arguments.
template <typename EventArgs, typename... Args>
void DispatchEvent(Control* const original_sender,
- events::RoutedEvent<EventArgs>* (Control::*event_ptr)(),
+ event::RoutedEvent<EventArgs>* (Control::*event_ptr)(),
Control* const last_receiver, Args&&... args) {
std::list<Control*> receive_list;
@@ -97,232 +93,31 @@ Control* FindLowestCommonAncestor(Control* left, Control* right) {
}
} // namespace
-
-inline Point PiToDip(const POINT& pi_point) {
- return Point(graph::PixelToDipX(pi_point.x), graph::PixelToDipY(pi_point.y));
-}
-
-inline POINT DipToPi(const Point& dip_point) {
- POINT result;
- result.x = graph::DipToPixelX(dip_point.x);
- result.y = graph::DipToPixelY(dip_point.y);
- return result;
-}
-
Window* Window::CreateOverlapped() {
return new Window(tag_overlapped_constructor{});
}
-Window* Window::CreatePopup(Window* parent, const bool caption) {
- return new Window(tag_popup_constructor{}, parent, caption);
-}
Window::Window(tag_overlapped_constructor) {
- BeforeCreateHwnd();
-
- const auto window_manager = WindowManager::GetInstance();
-
- hwnd_ =
- CreateWindowEx(0, window_manager->GetGeneralWindowClass()->GetName(), L"",
- WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr,
- Application::GetInstance()->GetInstanceHandle(), nullptr);
-
- if (hwnd_ == nullptr)
- throw Win32Error(::GetLastError(), "Failed to create window.");
-
- AfterCreateHwnd(window_manager);
-}
-
-Window::Window(tag_popup_constructor, Window* parent, const bool caption) {
- assert(parent == nullptr ||
- parent->IsWindowValid()); // Parent window is not valid.
-
- BeforeCreateHwnd();
-
- parent_window_ = parent;
-
- const auto window_manager = WindowManager::GetInstance();
-
- hwnd_ = CreateWindowEx(
- 0, window_manager->GetGeneralWindowClass()->GetName(), L"",
- caption ? (WS_POPUPWINDOW | WS_CAPTION) : WS_POPUP, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- parent == nullptr ? nullptr : parent->GetWindowHandle(), nullptr,
- Application::GetInstance()->GetInstanceHandle(), nullptr);
-
- if (hwnd_ == nullptr)
- throw Win32Error(::GetLastError(), "Failed to create window.");
-
- AfterCreateHwnd(window_manager);
-}
-
-void Window::BeforeCreateHwnd() { window_ = this; }
-
-void Window::AfterCreateHwnd(WindowManager* window_manager) {
- window_manager->RegisterWindow(hwnd_, this);
-
- render_target_.reset(
- new graph::WindowRenderTarget(graph::GraphManager::GetInstance(), hwnd_));
-
+ native_window_ = platform::UiApplication::GetInstance()->CreateWindow(nullptr);
render_object_.reset(new render::WindowRenderObject(this));
}
Window::~Window() {
-
TraverseDescendants(
[this](Control* control) { control->OnDetachToWindow(this); });
}
-StringView Window::GetControlType() const { return control_type; }
+std::wstring_view Window::GetControlType() const { return control_type; }
render::RenderObject* Window::GetRenderObject() const {
return render_object_.get();
}
-bool Window::HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param,
- LPARAM l_param, LRESULT& result) {
- events::WindowNativeMessageEventArgs args(this, this,
- {hwnd, msg, w_param, l_param});
- native_message_event_.Raise(args);
- if (args.GetResult().has_value()) {
- result = args.GetResult().value();
- return true;
- }
-
- switch (msg) {
- case WM_PAINT:
- OnPaintInternal();
- result = 0;
- return true;
- case WM_ERASEBKGND:
- result = 1;
- return true;
- case WM_SETFOCUS:
- OnSetFocusInternal();
- result = 0;
- return true;
- case WM_KILLFOCUS:
- OnKillFocusInternal();
- result = 0;
- return true;
- case WM_MOUSEMOVE: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseMoveInternal(point);
- result = 0;
- return true;
- }
- case WM_LBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Left, point);
- result = 0;
- return true;
- }
- case WM_LBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Left, point);
- result = 0;
- return true;
- }
- case WM_RBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Right, point);
- result = 0;
- return true;
- }
- case WM_RBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Right, point);
- result = 0;
- return true;
- }
- case WM_MBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Middle, point);
- result = 0;
- return true;
- }
- case WM_MBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Middle, point);
- result = 0;
- return true;
- }
- case WM_MOUSEWHEEL:
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- ScreenToClient(hwnd, &point);
- OnMouseWheelInternal(GET_WHEEL_DELTA_WPARAM(w_param), point);
- result = 0;
- return true;
- case WM_KEYDOWN:
- OnKeyDownInternal(static_cast<int>(w_param));
- result = 0;
- return true;
- case WM_KEYUP:
- OnKeyUpInternal(static_cast<int>(w_param));
- result = 0;
- return true;
- case WM_CHAR:
- OnCharInternal(static_cast<wchar_t>(w_param));
- result = 0;
- return true;
- case WM_SIZE:
- OnResizeInternal(LOWORD(l_param), HIWORD(l_param));
- result = 0;
- return true;
- case WM_ACTIVATE:
- if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE)
- OnActivatedInternal();
- else if (w_param == WA_INACTIVE)
- OnDeactivatedInternal();
- result = 0;
- return true;
- case WM_DESTROY:
- OnDestroyInternal();
- result = 0;
- return true;
- default:
- return false;
- }
-}
-
-Point Window::GetMousePosition() {
- if (!IsWindowValid()) return Point::Zero();
- POINT point;
- ::GetCursorPos(&point);
- ::ScreenToClient(hwnd_, &point);
- return PiToDip(point);
-}
-
bool Window::RequestFocusFor(Control* control) {
assert(control != nullptr); // The control to request focus can't be null.
// You can set it as the window.
- if (!IsWindowValid()) return false;
-
- if (!window_focus_) {
- focus_control_ = control;
- ::SetFocus(hwnd_);
- return true; // event dispatch will be done in window message handling
- // function "OnSetFocusInternal".
- }
-
if (focus_control_ == control) return true;
DispatchEvent(focus_control_, &Control::LoseFocusEvent, nullptr, false);
@@ -336,41 +131,6 @@ bool Window::RequestFocusFor(Control* control) {
Control* Window::GetFocusControl() { return focus_control_; }
-Control* Window::CaptureMouseFor(Control* control) {
- if (control != nullptr) {
- ::SetCapture(hwnd_);
- std::swap(mouse_capture_control_, control);
- DispatchMouseHoverControlChangeEvent(
- control ? control : mouse_hover_control_, mouse_capture_control_,
- GetMousePosition());
- return control;
- } else {
- return ReleaseCurrentMouseCapture();
- }
-}
-
-Control* Window::ReleaseCurrentMouseCapture() {
- if (mouse_capture_control_) {
- const auto previous = mouse_capture_control_;
- mouse_capture_control_ = nullptr;
- ::ReleaseCapture();
- DispatchMouseHoverControlChangeEvent(previous, mouse_hover_control_,
- GetMousePosition());
- return previous;
- } else {
- return nullptr;
- }
-}
-
-#ifdef CRU_DEBUG_LAYOUT
-void Window::SetDebugLayout(const bool value) {
- if (debug_layout_ != value) {
- debug_layout_ = value;
- InvalidateDraw();
- }
-}
-#endif
-
void Window::OnChildChanged(Control* old_child, Control* new_child) {
if (old_child) render_object_->RemoveChild(0);
if (new_child) render_object_->AddChild(new_child->GetRenderObject(), 0);
@@ -380,32 +140,9 @@ Control* Window::HitTest(const Point& point) {
return render_object_->HitTest(point)->GetAttachedControl();
}
-RECT Window::GetClientRectPixel() {
- RECT rect{};
- GetClientRect(hwnd_, &rect);
- return rect;
-}
-
-bool Window::IsMessageInQueue(UINT message) {
- MSG msg;
- return ::PeekMessageW(&msg, hwnd_, message, message, PM_NOREMOVE) != 0;
-}
-
-void Window::SetCursorInternal(HCURSOR cursor) {
- if (IsWindowValid()) {
- ::SetClassLongPtrW(GetWindowHandle(), GCLP_HCURSOR,
- reinterpret_cast<LONG_PTR>(cursor));
- if (mouse_hover_control_ != nullptr) ::SetCursor(cursor);
- }
-}
-
-void Window::OnDestroyInternal() {
- WindowManager::GetInstance()->UnregisterWindow(hwnd_);
- hwnd_ = nullptr;
- if (delete_this_on_destroy_) InvokeLater([this] { delete this; });
-}
+void Window::OnNativeDestroy() { delete this; }
-void Window::OnPaintInternal() {
+void Window::OnNativePaint() {
render_target_->SetAsTarget();
auto device_context =
diff --git a/src/ui/window.hpp b/src/ui/window.hpp
deleted file mode 100644
index f38743dc..00000000
--- a/src/ui/window.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-#pragma once
-#include "cru/common/pre_config.hpp"
-
-#include <map>
-#include <memory>
-
-#include "content_control.hpp"
-#include "events/ui_event.hpp"
-#include "window_class.hpp"
-
-
-namespace cru::ui {
-
-
-class Window final : public ContentControl {
- public:
- static constexpr auto control_type = L"Window";
-
- public:
- static Window* CreateOverlapped();
- static Window* CreatePopup(Window* parent, bool caption = false);
-
- private:
- struct tag_overlapped_constructor {};
- struct tag_popup_constructor {};
-
- explicit Window(tag_overlapped_constructor);
- Window(tag_popup_constructor, Window* parent, bool caption);
-
- void BeforeCreateHwnd();
- void AfterCreateHwnd(WindowManager* window_manager);
-
- public:
- Window(const Window& other) = delete;
- Window(Window&& other) = delete;
- Window& operator=(const Window& other) = delete;
- Window& operator=(Window&& other) = delete;
- ~Window() override;
-
- public:
- StringView GetControlType() const override final;
-
- render::RenderObject* GetRenderObject() const override;
-
-
-
-
- //*************** region: window operations ***************
-
- // Get the client size.
- Size GetClientSize();
-
- // Set the client size and repaint.
- void SetClientSize(const Size& size);
-
- // Get the rect of the window containing frame.
- // The lefttop of the rect is relative to screen lefttop.
- Rect GetWindowRect();
-
- // Set the rect of the window containing frame.
- // The lefttop of the rect is relative to screen lefttop.
- void SetWindowRect(const Rect& rect);
-
- // Set the lefttop of the window relative to screen.
- void SetWindowPosition(const Point& position);
-
- Point PointToScreen(const Point& point);
-
- Point PointFromScreen(const Point& point);
-
- // Handle the raw window message.
- // Return true if the message is handled and get the result through "result"
- // argument. Return false if the message is not handled.
- bool HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param,
- LRESULT& result);
-
- //*************** region: mouse ***************
-
- Point GetMousePosition();
-
- Control* GetMouseHoverControl() const { return mouse_hover_control_; }
-
- //*************** region: focus ***************
-
- // Request focus for specified control.
- bool RequestFocusFor(Control* control);
-
- // Get the control that has focus.
- Control* GetFocusControl();
-
- //*************** region: mouse capture ***************
-
- Control* CaptureMouseFor(Control* control);
- Control* ReleaseCurrentMouseCapture();
-
- //*************** region: events ***************
- public:
- Event<events::UiEventArgs>* ActivatedEvent() { return &activated_event_; }
- Event<events::UiEventArgs>* DeactivatedEvent() { return &deactivated_event_; }
- Event<events::WindowNativeMessageEventArgs>* NativeMessageEvent() {
- return &native_message_event_;
- }
-
- private:
- Event<events::UiEventArgs> activated_event_;
- Event<events::UiEventArgs> deactivated_event_;
- Event<events::WindowNativeMessageEventArgs> native_message_event_;
-
- protected:
- void OnChildChanged(Control* old_child, Control* new_child) override;
-
- private:
- Control* HitTest(const Point& point);
-
- //*************** region: native operations ***************
-
- // Get the client rect in pixel.
- RECT GetClientRectPixel();
-
- bool IsMessageInQueue(UINT message);
-
- void SetCursorInternal(HCURSOR cursor);
-
- //*************** 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(MouseButton button, POINT point);
- void OnMouseUpInternal(MouseButton button, POINT point);
-
- void OnMouseWheelInternal(short delta, POINT point);
- void OnKeyDownInternal(int virtual_code);
- void OnKeyUpInternal(int virtual_code);
- void OnCharInternal(wchar_t c);
-
- void OnActivatedInternal();
- void OnDeactivatedInternal();
-
- //*************** region: event dispatcher helper ***************
-
- void DispatchMouseHoverControlChangeEvent(Control* old_control,
- Control* new_control,
- const Point& point);
-
- private:
- std::shared_ptr<graph::WindowRenderTarget> render_target_{};
- std::shared_ptr<render::WindowRenderObject> render_object_{};
-
- Control* mouse_hover_control_ = nullptr;
-
- bool window_focus_ = false;
- Control* focus_control_ = this; // "focus_control_" can't be nullptr
- Control* mouse_capture_control_ = nullptr;
-};
-} // namespace cru::ui
diff --git a/src/util/math_util.hpp b/src/util/math_util.hpp
deleted file mode 100644
index 01348641..00000000
--- a/src/util/math_util.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-#include "pre.hpp"
-
-#include <optional>
-#include <type_traits>
-
-namespace cru::util {
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const std::optional<T> min,
- const std::optional<T> max) {
- if (min.has_value() && n < min.value()) return min.value();
- if (max.has_value() && n > max.value()) return max.value();
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const T min, const T max) {
- if (n < min) return min;
- if (n > max) return max;
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const std::nullopt_t, const std::optional<T> max) {
- if (max.has_value() && n > max.value()) return max.value();
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const std::optional<T> min, const std::nullopt_t) {
- if (min.has_value() && n < min.value()) return min.value();
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const std::nullopt_t, const T max) {
- if (n > max) return max;
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-float Coerce(const T n, const T min, const std::nullopt_t) {
- if (n < min) return min;
- return n;
-}
-
-template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
-T AtLeast0(const T value) {
- return value < static_cast<T>(0) ? static_cast<T>(0) : value;
-}
-} // namespace cru::util