diff options
author | crupest <crupest@outlook.com> | 2018-09-24 00:16:53 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-09-24 00:16:53 +0800 |
commit | 977c766e2337fea238804b8d8b97659361391ed0 (patch) | |
tree | ff3438e5b0517c52412cfa497d1d2a0ed314cf79 | |
parent | be84ddd03d3b59c0c27aa538d5ef5129f94d511c (diff) | |
download | cru-977c766e2337fea238804b8d8b97659361391ed0.tar.gz cru-977c766e2337fea238804b8d8b97659361391ed0.tar.bz2 cru-977c766e2337fea238804b8d8b97659361391ed0.zip |
Develop basic function of textbox.
-rw-r--r-- | CruUI/application.cpp | 6 | ||||
-rw-r--r-- | CruUI/application.h | 11 | ||||
-rw-r--r-- | CruUI/base.cpp | 2 | ||||
-rw-r--r-- | CruUI/main.cpp | 8 | ||||
-rw-r--r-- | CruUI/ui/control.cpp | 6 | ||||
-rw-r--r-- | CruUI/ui/control.h | 6 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.cpp | 42 | ||||
-rw-r--r-- | CruUI/ui/controls/text_box.cpp | 65 | ||||
-rw-r--r-- | CruUI/ui/controls/text_box.h | 13 |
9 files changed, 105 insertions, 54 deletions
diff --git a/CruUI/application.cpp b/CruUI/application.cpp index 2d949edb..af38116f 100644 --- a/CruUI/application.cpp +++ b/CruUI/application.cpp @@ -105,7 +105,11 @@ namespace cru { debug_border_brush_ = graph::CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Crimson)); #endif - caret_blink_duration_ = std::chrono::milliseconds(::GetCaretBlinkTime()); + 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; } Application::~Application() diff --git a/CruUI/application.h b/CruUI/application.h index 521c3436..106e7171 100644 --- a/CruUI/application.h +++ b/CruUI/application.h @@ -28,6 +28,11 @@ namespace cru class TimerManager; + struct CaretInfo + { + std::chrono::milliseconds caret_blink_duration; + float half_caret_width; + }; class GodWindow : public Object { @@ -101,9 +106,9 @@ namespace cru return god_window_.get(); } - std::chrono::milliseconds GetCaretBlinkDuration() const + CaretInfo GetCaretInfo() const { - return caret_blink_duration_; + return caret_info_; } #ifdef CRU_DEBUG_DRAW_CONTROL_BORDER @@ -127,7 +132,7 @@ namespace cru Microsoft::WRL::ComPtr<ID2D1Brush> debug_border_brush_; #endif - std::chrono::milliseconds caret_blink_duration_; + CaretInfo caret_info_; }; diff --git a/CruUI/base.cpp b/CruUI/base.cpp index c6b57e33..f5868170 100644 --- a/CruUI/base.cpp +++ b/CruUI/base.cpp @@ -13,7 +13,7 @@ namespace cru const auto length = ::WideCharToMultiByte(CP_UTF8, 0, string.data(), -1, nullptr, 0, nullptr, nullptr); MultiByteString result; result.reserve(length); - if (::WideCharToMultiByte(CP_UTF8, 0, string.data(), -1, result.data(), result.capacity(), nullptr, nullptr) == 0) + if (::WideCharToMultiByte(CP_UTF8, 0, string.data(), -1, result.data(), static_cast<int>(result.capacity()), nullptr, nullptr) == 0) throw Win32Error(::GetLastError(), "Failed to convert wide string to UTF-8."); return result; } diff --git a/CruUI/main.cpp b/CruUI/main.cpp index 56d42894..3d801964 100644 --- a/CruUI/main.cpp +++ b/CruUI/main.cpp @@ -6,6 +6,7 @@ #include "ui/controls/button.h" #include "ui/controls/margin_container.h" #include "ui/events/ui_event.h" +#include "ui/controls/text_box.h" using cru::String; @@ -20,6 +21,7 @@ using cru::ui::controls::TextBlock; using cru::ui::controls::ToggleButton; using cru::ui::controls::Button; using cru::ui::controls::MarginContainer; +using cru::ui::controls::TextBox; int APIENTRY wWinMain( HINSTANCE hInstance, @@ -84,8 +86,9 @@ int APIENTRY wWinMain( }); */ + /* //test 2 - + const auto layout = CreateWithLayout<LinearLayout>(LayoutSideParams::Exactly(500), LayoutSideParams::Content()); layout->mouse_click_event.AddHandler([layout](cru::ui::events::MouseButtonEventArgs& args) @@ -137,6 +140,9 @@ int APIENTRY wWinMain( window.AddChild(layout); + */ + + window.AddChild(CreateWithLayout<TextBox>(LayoutSideParams::Stretch(), LayoutSideParams::Stretch())); window.Show(); diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp index eaf206ac..8aec8640 100644 --- a/CruUI/ui/control.cpp +++ b/CruUI/ui/control.cpp @@ -480,7 +480,7 @@ namespace cru { { } - void Control::OnChar(events::CharEvent& args) + void Control::OnChar(CharEventArgs& args) { } @@ -492,7 +492,7 @@ namespace cru { { } - void Control::OnCharCore(events::CharEvent& args) + void Control::OnCharCore(CharEventArgs& args) { } @@ -510,7 +510,7 @@ namespace cru { key_up_event.Raise(args); } - void Control::RaiseCharEvent(CharEvent& args) + void Control::RaiseCharEvent(CharEventArgs& args) { OnCharCore(args); OnChar(args); diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h index fa1158a4..d6cbae40 100644 --- a/CruUI/ui/control.h +++ b/CruUI/ui/control.h @@ -285,15 +285,15 @@ namespace cru //*************** region: keyboard event *************** virtual void OnKeyDown(events::KeyEventArgs& args); virtual void OnKeyUp(events::KeyEventArgs& args); - virtual void OnChar(events::CharEvent& args); + virtual void OnChar(events::CharEventArgs& args); virtual void OnKeyDownCore(events::KeyEventArgs& args); virtual void OnKeyUpCore(events::KeyEventArgs& args); - virtual void OnCharCore(events::CharEvent& args); + virtual void OnCharCore(events::CharEventArgs& args); void RaiseKeyDownEvent(events::KeyEventArgs& args); void RaiseKeyUpEvent(events::KeyEventArgs& args); - void RaiseCharEvent(events::CharEvent& args); + void RaiseCharEvent(events::CharEventArgs& args); //*************** region: focus event *************** virtual void OnGetFocus(events::FocusChangeEventArgs& args); diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp index 4ecbb672..93d66ba6 100644 --- a/CruUI/ui/controls/text_block.cpp +++ b/CruUI/ui/controls/text_block.cpp @@ -98,31 +98,28 @@ namespace cru void TextBlock::OnDraw(ID2D1DeviceContext* device_context) { Control::OnDraw(device_context); - if (text_layout_ != nullptr) + if (selected_range_.has_value()) { - if (selected_range_.has_value()) + DWRITE_TEXT_METRICS text_metrics{}; + ThrowIfFailed(text_layout_->GetMetrics(&text_metrics)); + const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth; + + Vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count); + UINT32 actual_count; + text_layout_->HitTestTextRange( + selected_range_.value().position, selected_range_.value().count, + 0, 0, + hit_test_metrics.data(), metrics_count, &actual_count + ); + + hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, hit_test_metrics.cend()); + + for (const auto& metrics : hit_test_metrics) { - DWRITE_TEXT_METRICS text_metrics{}; - ThrowIfFailed(text_layout_->GetMetrics(&text_metrics)); - const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth; - - Vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count); - UINT32 actual_count; - text_layout_->HitTestTextRange( - selected_range_.value().position, selected_range_.value().count, - 0, 0, - hit_test_metrics.data(), metrics_count, &actual_count - ); - - hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, hit_test_metrics.cend()); - - for (const auto& metrics : hit_test_metrics) - { - device_context->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top, metrics.left + metrics.width, metrics.top + metrics.height), 3, 3), selection_brush_.Get()); - } + device_context->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top, metrics.left + metrics.width, metrics.top + metrics.height), 3, 3), selection_brush_.Get()); } - device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get()); } + device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get()); } namespace @@ -202,9 +199,6 @@ namespace cru Size TextBlock::OnMeasure(const Size& available_size) { - if (text_.empty()) - return Size::Zero(); - const auto layout_params = GetLayoutParams(); if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch) diff --git a/CruUI/ui/controls/text_box.cpp b/CruUI/ui/controls/text_box.cpp index 586bc017..53417d40 100644 --- a/CruUI/ui/controls/text_box.cpp +++ b/CruUI/ui/controls/text_box.cpp @@ -1,5 +1,7 @@ #include "text_box.h" +#include <cwctype> + #include "graph/graph.h" #include "exception.h" @@ -15,15 +17,20 @@ namespace cru::ui::controls TextBox::TextBox(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format, const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : Control(false) { - text_format_ = init_text_format; + text_format_ = init_text_format == nullptr ? graph::CreateDefaultTextFormat() : init_text_format; + + RecreateTextLayout(); - if (init_brush == nullptr) - brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)); - else - brush_ = init_brush; + brush_ = init_brush == nullptr ? CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)) : init_brush; caret_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)); + caret_action_ = CreateActionPtr([this] + { + is_caret_show_ = !is_caret_show_; + Repaint(); + }); + //selection_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue)); } @@ -66,6 +73,14 @@ namespace cru::ui::controls if (text_layout_ != nullptr) { device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get()); + if (is_caret_show_) + { + const auto caret_half_width = Application::GetInstance()->GetCaretInfo().half_caret_width; + FLOAT x, y; + DWRITE_HIT_TEST_METRICS metrics{}; + ThrowIfFailed(text_layout_->HitTestTextPosition(position_, FALSE, &x, &y, &metrics)); + device_context->FillRectangle(D2D1::RectF(metrics.left - caret_half_width, metrics.top, metrics.left + caret_half_width, metrics.top + metrics.height), caret_brush_.Get()); + } } } @@ -98,7 +113,8 @@ namespace cru::ui::controls { Control::OnGetFocusCore(args); assert(caret_timer_ == nullptr); - caret_timer_ = SetInterval(Application::GetInstance()->GetCaretBlinkDuration(), caret_action_); + is_caret_show_ = true; + caret_timer_ = SetInterval(Application::GetInstance()->GetCaretInfo().caret_blink_duration, caret_action_); } void TextBox::OnLoseFocusCore(events::FocusChangeEventArgs& args) @@ -106,13 +122,35 @@ namespace cru::ui::controls Control::OnLoseFocusCore(args); assert(caret_timer_ != nullptr); caret_timer_->Cancel(); + is_caret_show_ = false; } - Size TextBox::OnMeasure(const Size& available_size) + void TextBox::OnCharCore(events::CharEventArgs& args) { - if (text_.empty()) - return Size::Zero(); + Control::OnCharCore(args); + if (args.GetChar() == L'\b') + { + auto text = GetText(); + if (!text.empty() && position_ > 0) + { + const auto position = --position_; + text.erase(position); + SetText(text); + } + return; + } + + if (std::iswprint(args.GetChar())) + { + const auto position = position_++; + auto text = GetText(); + text.insert(text.cbegin() + position, { args.GetChar() }); + SetText(text); + } + } + Size TextBox::OnMeasure(const Size& available_size) + { const auto layout_params = GetLayoutParams(); if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch) @@ -174,17 +212,10 @@ namespace cru::ui::controls void TextBox::RecreateTextLayout() { - if (text_.empty()) - { - text_layout_ = nullptr; - return; - } + assert(text_format_ != nullptr); const auto dwrite_factory = GetDWriteFactory(); - if (text_format_ == nullptr) - text_format_ = graph::CreateDefaultTextFormat(); - const auto&& size = GetSize(); ThrowIfFailed(dwrite_factory->CreateTextLayout( diff --git a/CruUI/ui/controls/text_box.h b/CruUI/ui/controls/text_box.h index 68235c67..5fe14782 100644 --- a/CruUI/ui/controls/text_box.h +++ b/CruUI/ui/controls/text_box.h @@ -7,6 +7,14 @@ namespace cru::ui::controls { class TextBox : public Control { + public: + static TextBox* Create( + const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr, + const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr) + { + return new TextBox(init_text_format, init_brush); + } + protected: explicit TextBox( const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr, @@ -46,9 +54,11 @@ namespace cru::ui::controls void OnMouseDownCore(events::MouseButtonEventArgs& args) override final; - void OnGetFocusCore(events::FocusChangeEventArgs& args) override; + void OnGetFocusCore(events::FocusChangeEventArgs& args) override final; void OnLoseFocusCore(events::FocusChangeEventArgs& args) override final; + void OnCharCore(events::CharEventArgs& args) override final; + Size OnMeasure(const Size& available_size) override final; private: @@ -69,5 +79,6 @@ namespace cru::ui::controls TimerTask caret_timer_; ActionPtr caret_action_; + bool is_caret_show_; }; } |