diff options
Diffstat (limited to 'src/ui/control.cpp')
-rw-r--r-- | src/ui/control.cpp | 147 |
1 files changed, 123 insertions, 24 deletions
diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 8b91b25a..2a81427a 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -8,6 +8,7 @@ #include "exception.hpp" #include "cru_debug.hpp" #include "convert_util.hpp" +#include "math_util.hpp" #ifdef CRU_DEBUG_LAYOUT #include "ui_manager.hpp" @@ -191,26 +192,67 @@ namespace cru::ui bool Control::IsPointInside(const Point & point) { - if (border_geometry_ != nullptr) + const auto border_geometry = geometry_info_.border_geometry; + if (border_geometry != nullptr) { if (IsBordered()) { BOOL contains; - border_geometry_->FillContainsPoint(Convert(point), D2D1::Matrix3x2F::Identity(), &contains); + border_geometry->FillContainsPoint(Convert(point), D2D1::Matrix3x2F::Identity(), &contains); if (!contains) - border_geometry_->StrokeContainsPoint(Convert(point), GetBorderProperty().GetStrokeWidth(), nullptr, D2D1::Matrix3x2F::Identity(), &contains); + border_geometry->StrokeContainsPoint(Convert(point), GetBorderProperty().GetStrokeWidth(), nullptr, D2D1::Matrix3x2F::Identity(), &contains); return contains != 0; } else { BOOL contains; - border_geometry_->FillContainsPoint(Convert(point), D2D1::Matrix3x2F::Identity(), &contains); + border_geometry->FillContainsPoint(Convert(point), D2D1::Matrix3x2F::Identity(), &contains); return contains != 0; } } return false; } + Control* Control::HitTest(const Point& point) + { + const auto point_inside = IsPointInside(point); + + if (IsClipContent()) + { + if (!point_inside) + return nullptr; + if (geometry_info_.content_geometry != nullptr) + { + BOOL contains; + ThrowIfFailed(geometry_info_.content_geometry->FillContainsPoint(Convert(point), D2D1::Matrix3x2F::Identity(), &contains)); + if (contains == 0) + return this; + } + } + + const auto& children = GetChildren(); + + for (auto i = children.crbegin(); i != children.crend(); ++i) + { + const auto&& lefttop = (*i)->GetPositionRelative(); + const auto&& coerced_point = Point(point.x - lefttop.x, point.y - lefttop.y); + const auto child_hit_test_result = (*i)->HitTest(coerced_point); + if (child_hit_test_result != nullptr) + return child_hit_test_result; + } + + return point_inside ? this : nullptr; + } + + void Control::SetClipContent(const bool clip) + { + if (clip_content_ == clip) + return; + + clip_content_ = clip; + InvalidateDraw(); + } + void Control::Draw(ID2D1DeviceContext* device_context) { D2D1::Matrix3x2F old_transform; @@ -219,11 +261,20 @@ namespace cru::ui const auto position = GetPositionRelative(); device_context->SetTransform(old_transform * D2D1::Matrix3x2F::Translation(position.x, position.y)); + OnDrawDecoration(device_context); + + const auto set_layer = geometry_info_.content_geometry != nullptr && IsClipContent(); + if (set_layer) + device_context->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), geometry_info_.content_geometry.Get()), nullptr); + OnDrawCore(device_context); for (auto child : GetChildren()) child->Draw(device_context); + if (set_layer) + device_context->PopLayer(); + device_context->SetTransform(old_transform); } @@ -266,6 +317,7 @@ namespace cru::ui { SetPositionRelative(rect.GetLeftTop()); SetSize(rect.GetSize()); + AfterLayoutSelf(); OnLayoutCore(Rect(Point::Zero(), rect.GetSize())); } @@ -335,7 +387,7 @@ namespace cru::ui void Control::UpdateBorder() { - RegenerateBorderGeometry(); + RegenerateGeometryInfo(); InvalidateLayout(); InvalidateDraw(); } @@ -367,7 +419,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnAttachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } @@ -379,7 +430,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnDetachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } @@ -394,9 +444,9 @@ namespace cru::ui window_ = nullptr; } - void Control::OnDrawCore(ID2D1DeviceContext* device_context) + void Control::OnDrawDecoration(ID2D1DeviceContext* device_context) { - #ifdef CRU_DEBUG_LAYOUT +#ifdef CRU_DEBUG_LAYOUT if (GetWindow()->IsDebugLayout()) { if (padding_geometry_ != nullptr) @@ -407,17 +457,21 @@ namespace cru::ui } #endif - if (is_bordered_ && border_geometry_ != nullptr) + if (is_bordered_ && geometry_info_.border_geometry != nullptr) device_context->DrawGeometry( - border_geometry_.Get(), + geometry_info_.border_geometry.Get(), GetBorderProperty().GetBrush().Get(), GetBorderProperty().GetStrokeWidth(), GetBorderProperty().GetStrokeStyle().Get() ); + } + void Control::OnDrawCore(ID2D1DeviceContext* device_context) + { + const auto ground_geometry = geometry_info_.padding_content_geometry; //draw background. - if (in_border_geometry_ != nullptr && background_brush_ != nullptr) - device_context->FillGeometry(in_border_geometry_.Get(), background_brush_.Get()); + if (ground_geometry != nullptr && background_brush_ != nullptr) + device_context->FillGeometry(ground_geometry.Get(), background_brush_.Get()); const auto padding_rect = GetRect(RectRange::Padding); graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(padding_rect.left, padding_rect.top), [this](ID2D1DeviceContext* device_context) @@ -439,8 +493,8 @@ namespace cru::ui //draw foreground. - if (in_border_geometry_ != nullptr && foreground_brush_ != nullptr) - device_context->FillGeometry(in_border_geometry_.Get(), foreground_brush_.Get()); + if (ground_geometry != nullptr && foreground_brush_ != nullptr) + device_context->FillGeometry(ground_geometry.Get(), foreground_brush_.Get()); graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(padding_rect.left, padding_rect.top), [this](ID2D1DeviceContext* device_context) { @@ -502,7 +556,7 @@ namespace cru::ui void Control::OnSizeChangedCore(SizeChangedEventArgs & args) { - RegenerateBorderGeometry(); + RegenerateGeometryInfo(); #ifdef CRU_DEBUG_LAYOUT margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder)); padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content)); @@ -523,7 +577,7 @@ namespace cru::ui size_changed_event.Raise(args); } - void Control::RegenerateBorderGeometry() + void Control::RegenerateGeometryInfo() { if (IsBordered()) { @@ -536,10 +590,10 @@ namespace cru::ui ThrowIfFailed( graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRoundedRectangleGeometry(bound_rounded_rect, &geometry) ); - border_geometry_ = std::move(geometry); + geometry_info_.border_geometry = std::move(geometry); - const auto in_border_rect = GetRect(RectRange::Padding); - const auto in_border_rounded_rect = D2D1::RoundedRect(Convert(in_border_rect), + const auto padding_rect = GetRect(RectRange::Padding); + const auto in_border_rounded_rect = D2D1::RoundedRect(Convert(padding_rect), GetBorderProperty().GetRadiusX() - GetBorderProperty().GetStrokeWidth() / 2.0f, GetBorderProperty().GetRadiusY() - GetBorderProperty().GetStrokeWidth() / 2.0f); @@ -547,7 +601,24 @@ namespace cru::ui ThrowIfFailed( graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRoundedRectangleGeometry(in_border_rounded_rect, &geometry2) ); - in_border_geometry_ = std::move(geometry2); + geometry_info_.padding_content_geometry = geometry2; + + + Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> geometry3; + ThrowIfFailed( + graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRectangleGeometry(Convert(GetRect(RectRange::Content)), &geometry3) + ); + Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry4; + ThrowIfFailed( + graph::GraphManager::GetInstance()->GetD2D1Factory()->CreatePathGeometry(&geometry4) + ); + Microsoft::WRL::ComPtr<ID2D1GeometrySink> sink; + geometry4->Open(&sink); + ThrowIfFailed( + geometry3->CombineWithGeometry(geometry2.Get(), D2D1_COMBINE_MODE_INTERSECT, D2D1::Matrix3x2F::Identity(), sink.Get()) + ); + sink->Close(); + geometry_info_.content_geometry = std::move(geometry4); } else { @@ -556,8 +627,14 @@ namespace cru::ui ThrowIfFailed( graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRectangleGeometry(Convert(bound_rect), &geometry) ); - border_geometry_ = geometry; - in_border_geometry_ = std::move(geometry); + geometry_info_.border_geometry = geometry; + geometry_info_.padding_content_geometry = std::move(geometry); + + Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> geometry2; + ThrowIfFailed( + graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRectangleGeometry(Convert(GetRect(RectRange::Content)), &geometry2) + ); + geometry_info_.content_geometry = std::move(geometry2); } } @@ -632,6 +709,16 @@ namespace cru::ui } + void Control::OnMouseWheel(events::MouseWheelEventArgs& args) + { + + } + + void Control::OnMouseWheelCore(events::MouseWheelEventArgs& args) + { + + } + void Control::RaiseMouseEnterEvent(MouseEventArgs& args) { OnMouseEnterCore(args); @@ -674,6 +761,13 @@ namespace cru::ui mouse_click_event.Raise(args); } + void Control::RaiseMouseWheelEvent(MouseWheelEventArgs& args) + { + OnMouseWheelCore(args); + OnMouseWheel(args); + mouse_wheel_event.Raise(args); + } + void Control::OnMouseClickBegin(MouseButton button) { @@ -834,7 +928,7 @@ namespace cru::ui auto parent = GetParent(); while (parent != nullptr) { - auto lp = parent->GetLayoutParams(); + const auto lp = parent->GetLayoutParams(); if (!stretch_width_determined) { @@ -969,6 +1063,11 @@ namespace cru::ui } } + void Control::AfterLayoutSelf() + { + + } + void Control::CheckAndNotifyPositionChanged() { if (this->old_position_ != this->position_) |