diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/base.hpp | 30 | ||||
-rw-r--r-- | src/main.cpp | 13 | ||||
-rw-r--r-- | src/math_util.hpp | 66 | ||||
-rw-r--r-- | src/ui/control.cpp | 13 | ||||
-rw-r--r-- | src/ui/control.hpp | 12 | ||||
-rw-r--r-- | src/ui/controls/linear_layout.cpp | 12 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.cpp | 249 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.hpp | 87 | ||||
-rw-r--r-- | src/ui/ui_base.hpp | 10 | ||||
-rw-r--r-- | src/ui/ui_manager.cpp | 6 | ||||
-rw-r--r-- | src/ui/ui_manager.hpp | 4 |
11 files changed, 437 insertions, 65 deletions
diff --git a/src/base.hpp b/src/base.hpp index 5d8cb9ce..fdd736a0 100644 --- a/src/base.hpp +++ b/src/base.hpp @@ -8,9 +8,6 @@ #include <stdexcept> #include <string_view> #include <chrono> -#include <optional> -// ReSharper disable once CppUnusedIncludeDirective -#include <type_traits> namespace cru { @@ -60,31 +57,4 @@ namespace cru if (!condition) throw std::invalid_argument(error_message.data()); } - - 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 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; - } - } diff --git a/src/main.cpp b/src/main.cpp index 376c03b8..5cc98a72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ #include "ui/controls/list_item.hpp" #include "ui/controls/popup_menu.hpp" #include "ui/controls/frame_layout.hpp" +#include "ui/controls/scroll_control.hpp" #include "graph/graph.hpp" using cru::String; @@ -27,6 +28,7 @@ using cru::ui::controls::Button; using cru::ui::controls::TextBox; using cru::ui::controls::ListItem; using cru::ui::controls::FrameLayout; +using cru::ui::controls::ScrollControl; int APIENTRY wWinMain( HINSTANCE hInstance, @@ -183,9 +185,16 @@ int APIENTRY wWinMain( } { - const auto text_block = CreateWithLayout<TextBlock>(LayoutSideParams::Stretch(), LayoutSideParams::Stretch(), L"This is a very very very very very long sentence!!!"); + const auto scroll_view = CreateWithLayout<ScrollControl>(LayoutSideParams::Stretch(), LayoutSideParams::Stretch()); + + scroll_view->SetVerticalScrollBarVisibility(ScrollControl::ScrollBarVisibility::Always); + + const auto text_block = TextBlock::Create( + L"Love myself I do. Not everything, but I love the good as well as the bad. I love my crazy lifestyle, and I love my hard discipline. I love my freedom of speech and the way my eyes get dark when I'm tired. I love that I have learned to trust people with my heart, even if it will get broken. I am proud of everything that I am and will become."); text_block->SetSelectable(true); - layout->AddChild(text_block); + + scroll_view->AddChild(text_block); + layout->AddChild(scroll_view); } layout->AddChild(CreateWithLayout<TextBlock>(LayoutSideParams::Content(Alignment::Start), LayoutSideParams::Content(), L"This is a little short sentence!!!")); diff --git a/src/math_util.hpp b/src/math_util.hpp new file mode 100644 index 00000000..7b286346 --- /dev/null +++ b/src/math_util.hpp @@ -0,0 +1,66 @@ +#pragma once + +// ReSharper disable once CppUnusedIncludeDirective +#include <type_traits> +#include <optional> + +namespace cru +{ + 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; + } +} diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 66f22c58..32909c75 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" @@ -316,6 +317,7 @@ namespace cru::ui { SetPositionRelative(rect.GetLeftTop()); SetSize(rect.GetSize()); + AfterLayoutSelf(); OnLayoutCore(Rect(Point::Zero(), rect.GetSize())); } @@ -385,7 +387,7 @@ namespace cru::ui void Control::UpdateBorder() { - RegenerateGeometries(); + RegenerateGeometryInfo(); InvalidateLayout(); InvalidateDraw(); } @@ -554,7 +556,7 @@ namespace cru::ui void Control::OnSizeChangedCore(SizeChangedEventArgs & args) { - RegenerateGeometries(); + RegenerateGeometryInfo(); #ifdef CRU_DEBUG_LAYOUT margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder)); padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content)); @@ -575,7 +577,7 @@ namespace cru::ui size_changed_event.Raise(args); } - void Control::RegenerateGeometries() + void Control::RegenerateGeometryInfo() { if (IsBordered()) { @@ -1044,6 +1046,11 @@ namespace cru::ui } } + void Control::AfterLayoutSelf() + { + + } + void Control::CheckAndNotifyPositionChanged() { if (this->old_position_ != this->position_) diff --git a/src/ui/control.hpp b/src/ui/control.hpp index 6c5b0ea5..1ce4afe3 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -32,7 +32,7 @@ namespace cru::ui friend class Window; friend class LayoutManager; - private: + protected: struct GeometryInfo { Microsoft::WRL::ComPtr<ID2D1Geometry> border_geometry = nullptr; @@ -309,7 +309,12 @@ namespace cru::ui void RaisePositionChangedEvent(events::PositionChangedEventArgs& args); void RaiseSizeChangedEvent(events::SizeChangedEventArgs& args); - void RegenerateGeometries(); + void RegenerateGeometryInfo(); + + const GeometryInfo& GetGeometryInfo() const + { + return geometry_info_; + } //*************** region: mouse event *************** virtual void OnMouseEnter(events::MouseEventArgs& args); @@ -366,6 +371,9 @@ namespace cru::ui virtual Size OnMeasureContent(const Size& available_size); virtual void OnLayoutContent(const Rect& rect); + // Called by Layout after set position and size. + virtual void AfterLayoutSelf(); + private: // Only for layout manager to use. // Check if the old position is updated to current position. diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp index 3789b305..8fb91513 100644 --- a/src/ui/controls/linear_layout.cpp +++ b/src/ui/controls/linear_layout.cpp @@ -2,6 +2,8 @@ #include <algorithm> +#include "math_util.hpp" + namespace cru::ui::controls { LinearLayout::LinearLayout(const Orientation orientation) @@ -10,16 +12,6 @@ namespace cru::ui::controls } - inline float AtLeast0(const float value) - { - return value < 0 ? 0 : value; - } - - inline Size AtLeast0(const Size& size) - { - return Size(AtLeast0(size.width), AtLeast0(size.height)); - } - StringView LinearLayout::GetControlType() const { return control_type; diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp index 6b6d899c..103a5c20 100644 --- a/src/ui/controls/scroll_control.cpp +++ b/src/ui/controls/scroll_control.cpp @@ -4,9 +4,16 @@ #include "cru_debug.hpp" #include "format.hpp" +#include "ui/convert_util.hpp" +#include "exception.hpp" +#include "math_util.hpp" +#include "ui/ui_manager.hpp" +#include "ui/window.hpp" namespace cru::ui::controls { + constexpr auto scroll_bar_width = 15.0f; + ScrollControl::ScrollControl(const bool container) : Control(container) { SetClipContent(true); @@ -17,6 +24,11 @@ namespace cru::ui::controls } + StringView ScrollControl::GetControlType() const + { + return control_type; + } + void ScrollControl::SetHorizontalScrollEnabled(const bool enable) { horizontal_scroll_enabled_ = enable; @@ -31,9 +43,50 @@ namespace cru::ui::controls InvalidateDraw(); } - Control* ScrollControl::HitTest(const Point& point) + void ScrollControl::SetHorizontalScrollBarVisibility(const ScrollBarVisibility visibility) { + if (visibility != horizontal_scroll_bar_visibility_) + { + horizontal_scroll_bar_visibility_ = visibility; + switch (visibility) + { + case ScrollBarVisibility::Always: + is_horizontal_scroll_bar_visible_ = true; + break; + case ScrollBarVisibility::None: + is_horizontal_scroll_bar_visible_ = false; + break; + case ScrollBarVisibility::Auto: + UpdateScrollBarVisibility(); + } + InvalidateDraw(); + } + } + void ScrollControl::SetVerticalScrollBarVisibility(const ScrollBarVisibility visibility) + { + if (visibility != vertical_scroll_bar_visibility_) + { + vertical_scroll_bar_visibility_ = visibility; + switch (visibility) + { + case ScrollBarVisibility::Always: + is_vertical_scroll_bar_visible_ = true; + break; + case ScrollBarVisibility::None: + is_vertical_scroll_bar_visible_ = false; + break; + case ScrollBarVisibility::Auto: + UpdateScrollBarVisibility(); + } + InvalidateDraw(); + } + + } + + void ScrollControl::SetScrollOffset(std::optional<float> x, std::optional<float> y) + { + CoerceAndSetOffsets(x.value_or(GetScrollOffsetX()), y.value_or(GetScrollOffsetY())); } void ScrollControl::SetViewWidth(const float length) @@ -54,13 +107,13 @@ namespace cru::ui::controls if (IsHorizontalScrollEnabled()) { if (layout_params->width.mode == MeasureMode::Content) - debug::DebugMessage(L"ScrollView: Width measure mode is Content and horizontal scroll is enabled. So Stretch is used instead."); + debug::DebugMessage(L"ScrollControl: Width measure mode is Content and horizontal scroll is enabled. So Stretch is used instead."); for (auto child : GetChildren()) { const auto child_layout_params = child->GetLayoutParams(); if (child_layout_params->width.mode == MeasureMode::Stretch) - throw std::runtime_error(Format("ScrollView: Horizontal scroll is enabled but a child {} 's width measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType()))); + throw std::runtime_error(Format("ScrollControl: Horizontal scroll is enabled but a child {} 's width measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType()))); } available_size_for_children.width = std::numeric_limits<float>::max(); @@ -69,13 +122,13 @@ namespace cru::ui::controls if (IsVerticalScrollEnabled()) { if (layout_params->height.mode == MeasureMode::Content) - debug::DebugMessage(L"ScrollView: Height measure mode is Content and vertical scroll is enabled. So Stretch is used instead."); + debug::DebugMessage(L"ScrollControl: Height measure mode is Content and vertical scroll is enabled. So Stretch is used instead."); for (auto child : GetChildren()) { const auto child_layout_params = child->GetLayoutParams(); if (child_layout_params->height.mode == MeasureMode::Stretch) - throw std::runtime_error(Format("ScrollView: Vertical scroll is enabled but a child {} 's height measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType()))); + throw std::runtime_error(Format("ScrollControl: Vertical scroll is enabled but a child {} 's height measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType()))); } available_size_for_children.height = std::numeric_limits<float>::max(); @@ -132,15 +185,193 @@ namespace cru::ui::controls { const auto size = control->GetDesiredSize(); // Ignore alignment, always center aligned. - auto&& calculate_anchor = [](const float anchor, const float layout_length, const float control_length) -> float + auto&& calculate_anchor = [](const float anchor, const float layout_length, const float control_length, const float offset) -> float { - return anchor + (layout_length - control_length) / 2; + return anchor + (layout_length - control_length) / 2 - offset; }; control->Layout(Rect(Point( - calculate_anchor(rect.left, layout_rect.width, size.width), - calculate_anchor(rect.top, layout_rect.height, size.height) + calculate_anchor(rect.left, layout_rect.width, size.width, offset_x_), + calculate_anchor(rect.top, layout_rect.height, size.height, offset_y_) ), size)); } } + + void ScrollControl::AfterLayoutSelf() + { + UpdateScrollBarBorderInfo(); + CoerceAndSetOffsets(offset_x_, offset_y_, false); + UpdateScrollBarVisibility(); + } + + void ScrollControl::OnDrawForeground(ID2D1DeviceContext* device_context) + { + Control::OnDrawForeground(device_context); + + const auto predefined = UiManager::GetInstance()->GetPredefineResources(); + + if (is_horizontal_scroll_bar_visible_) + { + device_context->FillRectangle( + Convert(horizontal_bar_info_.border), + predefined->scroll_bar_background_brush.Get() + ); + + device_context->FillRectangle( + Convert(horizontal_bar_info_.bar), + predefined->scroll_bar_brush.Get() + ); + + device_context->DrawLine( + Convert(horizontal_bar_info_.border.GetLeftTop()), + Convert(horizontal_bar_info_.border.GetRightTop()), + predefined->scroll_bar_border_brush.Get() + ); + } + + if (is_vertical_scroll_bar_visible_) + { + device_context->FillRectangle( + Convert(vertical_bar_info_.border), + predefined->scroll_bar_background_brush.Get() + ); + + device_context->FillRectangle( + Convert(vertical_bar_info_.bar), + predefined->scroll_bar_brush.Get() + ); + + device_context->DrawLine( + Convert(vertical_bar_info_.border.GetLeftTop()), + Convert(vertical_bar_info_.border.GetLeftBottom()), + predefined->scroll_bar_border_brush.Get() + ); + } + } + + void ScrollControl::OnMouseDownCore(events::MouseButtonEventArgs& args) + { + Control::OnMouseDownCore(args); + + if (args.GetMouseButton() == MouseButton::Left) + { + const auto point = args.GetPoint(this); + if (is_vertical_scroll_bar_visible_ && vertical_bar_info_.bar.IsPointInside(point)) + { + GetWindow()->CaptureMouseFor(this); + is_pressing_scroll_bar_ = Orientation::Vertical; + pressing_delta_ = point.y - vertical_bar_info_.bar.top; + return; + } + + if (is_horizontal_scroll_bar_visible_ && horizontal_bar_info_.bar.IsPointInside(point)) + { + GetWindow()->CaptureMouseFor(this); + pressing_delta_ = point.x - horizontal_bar_info_.bar.left; + is_pressing_scroll_bar_ = Orientation::Horizontal; + return; + } + } + } + + void ScrollControl::OnMouseMoveCore(events::MouseEventArgs& args) + { + Control::OnMouseMoveCore(args); + + const auto mouse_point = args.GetPoint(this); + + if (is_pressing_scroll_bar_ == Orientation::Horizontal) + { + const auto new_head_position = mouse_point.x - pressing_delta_; + const auto new_offset = new_head_position / horizontal_bar_info_.border.width * view_width_; + SetScrollOffset(new_offset, std::nullopt); + return; + } + + if (is_pressing_scroll_bar_ == Orientation::Vertical) + { + const auto new_head_position = mouse_point.y - pressing_delta_; + const auto new_offset = new_head_position / vertical_bar_info_.border.height * view_height_; + SetScrollOffset(std::nullopt, new_offset); + return; + } + } + + void ScrollControl::OnMouseUpCore(events::MouseButtonEventArgs& args) + { + Control::OnMouseUpCore(args); + + if (args.GetMouseButton() == MouseButton::Left && is_pressing_scroll_bar_.has_value()) + { + GetWindow()->ReleaseCurrentMouseCapture(); + is_pressing_scroll_bar_ = std::nullopt; + } + } + + void ScrollControl::CoerceAndSetOffsets(const float offset_x, const float offset_y, const bool update_children) + { + const auto old_offset_x = offset_x_; + const auto old_offset_y = offset_y_; + + const auto content_rect = GetRect(RectRange::Content); + offset_x_ = Coerce(offset_x, 0.0f, AtLeast0(view_width_ - content_rect.width)); + offset_y_ = Coerce(offset_y, 0.0f, AtLeast0(view_height_ - content_rect.height)); + UpdateScrollBarBarInfo(); + + if (update_children) + { + for (auto child : GetChildren()) + { + const auto old_position = child->GetPositionRelative(); + child->SetPositionRelative(Point( + old_position.x + old_offset_x - offset_x_, + old_position.y + old_offset_y - offset_y_ + )); + } + } + InvalidateDraw(); + } + + void ScrollControl::UpdateScrollBarVisibility() + { + const auto content_rect = GetRect(RectRange::Content); + if (GetHorizontalScrollBarVisibility() == ScrollBarVisibility::Auto) + is_horizontal_scroll_bar_visible_ = view_width_ > content_rect.width; + if (GetVerticalScrollBarVisibility() == ScrollBarVisibility::Auto) + is_vertical_scroll_bar_visible_ = view_height_ > content_rect.height; + } + + void ScrollControl::UpdateScrollBarBorderInfo() + { + const auto content_rect = GetRect(RectRange::Content); + horizontal_bar_info_.border = Rect(content_rect.left, content_rect.GetBottom() - scroll_bar_width, content_rect.width, scroll_bar_width); + vertical_bar_info_.border = Rect(content_rect.GetRight() - scroll_bar_width , content_rect.top, scroll_bar_width, content_rect.height); + } + + void ScrollControl::UpdateScrollBarBarInfo() + { + const auto content_rect = GetRect(RectRange::Content); + { + const auto& border = horizontal_bar_info_.border; + if (view_width_ <= content_rect.width) + horizontal_bar_info_.bar = border; + else + { + const auto bar_length = border.width * content_rect.width / view_width_; + const auto offset = border.width * offset_x_ / view_width_; + horizontal_bar_info_.bar = Rect(border.left + offset, border.top, bar_length, border.height); + } + } + { + const auto& border = vertical_bar_info_.border; + if (view_height_ <= content_rect.height) + vertical_bar_info_.bar = border; + else + { + const auto bar_length = border.height * content_rect.height / view_height_; + const auto offset = border.height * offset_y_ / view_height_; + vertical_bar_info_.bar = Rect(border.left, border.top + offset, border.width, bar_length); + } + } + } } diff --git a/src/ui/controls/scroll_control.hpp b/src/ui/controls/scroll_control.hpp index c39b18f4..faf192ad 100644 --- a/src/ui/controls/scroll_control.hpp +++ b/src/ui/controls/scroll_control.hpp @@ -1,17 +1,34 @@ #pragma once +#include <optional> +#include <initializer_list> + #include "ui/control.hpp" namespace cru::ui::controls { // Done: OnMeasureContent // Done: OnLayoutContent - // TODO: HitTest - // TODO: Draw - // TODO: ScrollBar + // Done: HitTest(no need) + // Done: Draw(no need) + // Done: API + // Done: ScrollBar // TODO: MouseEvent class ScrollControl : public Control { + private: + struct ScrollBarInfo + { + Rect border = Rect(); + Rect bar = Rect(); + }; + + enum class Orientation + { + Horizontal, + Vertical + }; + public: enum class ScrollBarVisibility { @@ -20,6 +37,16 @@ namespace cru::ui::controls Always }; + static ScrollControl* Create(const std::initializer_list<Control*>& children = std::initializer_list<Control*>{}) + { + const auto control = new ScrollControl(true); + for (auto child : children) + control->AddChild(child); + return control; + } + + static constexpr auto control_type = L"ScrollControl"; + protected: explicit ScrollControl(bool container); public: @@ -29,6 +56,7 @@ namespace cru::ui::controls ScrollControl& operator=(ScrollControl&& other) = delete; ~ScrollControl() override; + StringView GetControlType() const override final; bool IsHorizontalScrollEnabled() const { @@ -45,14 +73,20 @@ namespace cru::ui::controls void SetVerticalScrollEnabled(bool enable); - ScrollBarVisibility GetHorizontalScrollBarVisibility() const; + ScrollBarVisibility GetHorizontalScrollBarVisibility() const + { + return horizontal_scroll_bar_visibility_; + } + void SetHorizontalScrollBarVisibility(ScrollBarVisibility visibility); - ScrollBarVisibility GetVerticalScrollBarVisibility() const; - void SetVerticalScrollBarVisibility(ScrollBarVisibility visibility); - Control* HitTest(const Point& point) override final; + ScrollBarVisibility GetVerticalScrollBarVisibility() const + { + return vertical_scroll_bar_visibility_; + } + + void SetVerticalScrollBarVisibility(ScrollBarVisibility visibility); - protected: float GetViewWidth() const { return view_width_; @@ -63,12 +97,40 @@ namespace cru::ui::controls return view_height_; } + float GetScrollOffsetX() const + { + return offset_x_; + } + + float GetScrollOffsetY() const + { + return offset_y_; + } + + // nullopt for not set. value is auto-coerced. + void SetScrollOffset(std::optional<float> x, std::optional<float> y); + + protected: void SetViewWidth(float length); void SetViewHeight(float length); Size OnMeasureContent(const Size& available_size) override final; void OnLayoutContent(const Rect& rect) override final; + void AfterLayoutSelf() override; + + void OnDrawForeground(ID2D1DeviceContext* device_context) override; + + void OnMouseDownCore(events::MouseButtonEventArgs& args) override final; + void OnMouseMoveCore(events::MouseEventArgs& args) override final; + void OnMouseUpCore(events::MouseButtonEventArgs& args) override final; + + private: + void CoerceAndSetOffsets(float offset_x, float offset_y, bool update_children = true); + void UpdateScrollBarVisibility(); + void UpdateScrollBarBorderInfo(); + void UpdateScrollBarBarInfo(); + private: bool horizontal_scroll_enabled_ = true; bool vertical_scroll_enabled_ = true; @@ -76,10 +138,19 @@ namespace cru::ui::controls ScrollBarVisibility horizontal_scroll_bar_visibility_ = ScrollBarVisibility::Auto; ScrollBarVisibility vertical_scroll_bar_visibility_ = ScrollBarVisibility::Auto; + bool is_horizontal_scroll_bar_visible_ = false; + bool is_vertical_scroll_bar_visible_ = false; + float offset_x_ = 0.0f; float offset_y_ = 0.0f; float view_width_ = 0.0f; float view_height_ = 0.0f; + + ScrollBarInfo horizontal_bar_info_; + ScrollBarInfo vertical_bar_info_; + + std::optional<Orientation> is_pressing_scroll_bar_ = std::nullopt; + float pressing_delta_ = 0.0f; }; } diff --git a/src/ui/ui_base.hpp b/src/ui/ui_base.hpp index d9c9d0b2..aaba343e 100644 --- a/src/ui/ui_base.hpp +++ b/src/ui/ui_base.hpp @@ -150,6 +150,16 @@ namespace cru::ui return Point(left + width, top + height); } + constexpr Point GetLeftBottom() const + { + return Point(left, top + height); + } + + constexpr Point GetRightTop() const + { + return Point(left + width, top); + } + constexpr Size GetSize() const { return Size(width, height); diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp index 36fb2fb0..689a04a2 100644 --- a/src/ui/ui_manager.cpp +++ b/src/ui/ui_manager.cpp @@ -75,7 +75,11 @@ namespace cru::ui list_item_hover_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue))}, list_item_hover_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.3f))}, list_item_select_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::MediumBlue))}, - list_item_select_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.3f))} + list_item_select_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.3f))}, + + scroll_bar_background_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Gainsboro, 0.3f))}, + scroll_bar_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DimGray))}, + scroll_bar_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DimGray))} #ifdef CRU_DEBUG_LAYOUT , diff --git a/src/ui/ui_manager.hpp b/src/ui/ui_manager.hpp index 6b368e12..9ad68eff 100644 --- a/src/ui/ui_manager.hpp +++ b/src/ui/ui_manager.hpp @@ -61,6 +61,10 @@ namespace cru::ui Microsoft::WRL::ComPtr<ID2D1Brush> list_item_select_border_brush; Microsoft::WRL::ComPtr<ID2D1Brush> list_item_select_fill_brush; + //region ScrollControl + Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_background_brush; + Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_border_brush; + Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_brush; #ifdef CRU_DEBUG_LAYOUT //region debug |