Index: ui/views/layout/box_layout.h |
diff --git a/ui/views/layout/box_layout.h b/ui/views/layout/box_layout.h |
index 9a87984d51f77cec0caa488860fa6dc1986f9e28..d2930cc774c9f5700e328857909fe25197ada155 100644 |
--- a/ui/views/layout/box_layout.h |
+++ b/ui/views/layout/box_layout.h |
@@ -58,11 +58,60 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
// Use |inside_border_horizontal_spacing| and |
// |inside_border_vertical_spacing| to add additional space between the child |
// view area and the host view border. |between_child_spacing| controls the |
- // space in between child views. |
+ // space in between child views. Use view->SetProperty(kMarginsKey, |
+ // new gfx::Insets(xxx)) to add additional margins on a per-view basis. The |
+ // |collapse_margins_spacing| parameter controls whether or not adjacent |
+ // spacing/margins are collapsed base on the max of the two values. For the |
sky
2017/06/05 17:26:53
base->based
kylix_rd
2017/06/06 18:22:34
Done.
|
+ // cross axis, |collapse_margins_spacing| will collapse to the max of |
+ // inside_border_xxxxx_spacing and the max of the corresponding margin edge |
sky
2017/06/05 17:26:54
This can't be entirely correct, is it? Whether max
kylix_rd
2017/06/06 18:22:34
Done.
|
+ // from each view. |
+ // |
+ // Given the following views where V = view bounds, M = Margins property, |
+ // B = between child spacing, S = inside border spacing and |
+ // <space> = added margins for alignment |
+ // |
+ // MMMMM MMVVVVMM MMMM |
+ // VVVVM MMMM |
+ // VVVVM MMMM |
+ // VVVVM VVVV |
+ // MMMMM |
+ // |
+ // With collapse_margins_spacing = false, orientation = kHorizontal, |
+ // inside_border_spacing_horizontal = 2, inside_border_spacing_vertical = 2 |
+ // and between_child_spacing = 1: |
+ // |
+ // ----------------------- |
+ // SSSSSSSSSSSSSSSSSSSSSSS |
+ // SSSSSSSSSSSSSSSSSSSSSSS |
+ // SS MBMM MMBMMMMSS |
+ // SS MBMM MMBMMMMSS |
+ // SSMMMMMBMM MMBMMMMSS |
+ // SSVVVVMBMMVVVVMMBVVVVSS |
+ // SSVVVVMBMMVVVVMMBVVVVSS |
+ // SSVVVVMBMMVVVVMMBVVVVSS |
+ // SSMMMMMBMMVVVVMMBVVVVSS |
+ // SSSSSSSSSSSSSSSSSSSSSSS |
+ // SSSSSSSSSSSSSSSSSSSSSSS |
+ // ----------------------- |
+ // |
+ // Same as above except, collapse_margins_spacing = true. |
+ // |
+ // -------------------- |
+ // SS MMMMMMSS |
+ // SS MMMMMMSS |
+ // SSMMMMMM MMMMMMSS |
+ // SSVVVVMMVVVVMMVVVVSS |
+ // SSVVVVMMVVVVMMVVVVSS |
+ // SSVVVVMMVVVVMMVVVVSS |
+ // SSSSSSSSSSSSSSSSSSSS |
+ // SSSSSSSSSSSSSSSSSSSS |
+ // -------------------- |
+ // |
BoxLayout(Orientation orientation, |
int inside_border_horizontal_spacing, |
int inside_border_vertical_spacing, |
- int between_child_spacing); |
+ int between_child_spacing, |
+ bool collapse_margins_spacing = false); |
~BoxLayout() override; |
void set_main_axis_alignment(MainAxisAlignment main_axis_alignment) { |
@@ -105,6 +154,43 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
int GetPreferredHeightForWidth(const View* host, int width) const override; |
private: |
+ // This struct is used internally to "wrap" a child view in order to obviate |
+ // the need for the main layout logic to be fully aware of the per-view |
+ // margins when |collapse_margin_spacing_| is false. Since each view is a |
+ // rectangle of a certain size, this wrapper, coupled with any margins set |
+ // will increase the apparent size of the view along the main axis. All |
+ // necessary view size/position methods required for the layout logic add or |
+ // subtract the margins where appropriate to ensure the actual visible size of |
+ // the view doesn't include the margins. For the cross axis, the margins are |
+ // NOT included in the size/position calculations. BoxLayout will adjust the |
+ // bounding rectangle of the space used for layout using the maximum margin |
+ // for all views along the appropriate edge. |
+ // When |collapse_margin_spacing_| is true, this wrapper provides quick access |
+ // to the view's margins for use by the layout to collapse adjacent spacing |
+ // to the largest of the several values. |
+ class ViewWrapper { |
+ public: |
+ ViewWrapper(); |
+ ViewWrapper(const BoxLayout* layout, View* view); |
+ ~ViewWrapper(); |
+ int GetHeightForWidth(int width) const; |
+ const gfx::Insets& margins() const { return margins_; } |
+ gfx::Size GetPreferredSize() const; |
+ void SetBoundsRect(const gfx::Rect& bounds); |
+ View* view() const { return view_; } |
+ bool visible() const; |
+ |
+ private: |
+ View* view_; |
+ const BoxLayout* layout_; |
+ const Orientation orientation_; |
+ gfx::Insets margins_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ViewWrapper); |
+ }; |
+ |
+ using FlexMap = std::map<const View*, int>; |
+ |
// Returns the flex for the specified |view|. |
int GetFlexForView(const View* view) const; |
@@ -126,10 +212,64 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
// Returns the main axis size for the given view. |child_area_width| is needed |
// to calculate the height of the view when the orientation is vertical. |
- int MainAxisSizeForView(const View* view, int child_area_width) const; |
+ int MainAxisSizeForView(const ViewWrapper& view, int child_area_width) const; |
+ |
+ // Returns the |left| or |top| edge of the given inset based on the value of |
+ // |orientation_|. |
+ int MainAxisLeadingInset(const gfx::Insets& insets) const; |
+ |
+ // Returns the |right| or |bottom| edge of the given inset based on the value |
+ // of |orientation_|. |
+ int MainAxisTrailingInset(const gfx::Insets& insets) const; |
+ |
+ // Returns the left (|x|) or top (|y|) edge of the given rect based on the |
+ // value of |orientation_|. |
+ int CrossAxisLeadingEdge(const gfx::Rect& rect) const; |
+ |
+ // Returns the |left| or |top| edge of the given inset based on the value of |
+ // |orientation_|. |
+ int CrossAxisLeadingInset(const gfx::Insets& insets) const; |
+ |
+ // Returns the |right| or |bottom| edge of the given inset based on the value |
+ // of |orientation_|. |
+ int CrossAxisTrailingInset(const gfx::Insets& insets) const; |
+ |
+ // Returns the main axis margin spacing between the two views which is the max |
+ // of the right margin from the |left| view, the left margin of the |right| |
+ // view and |between_child_spacing_|. |
+ int MainAxisMarginBetweenViews(const ViewWrapper& left, |
+ const ViewWrapper& right) const; |
+ |
+ // Returns the outer margin along the main axis as insets. |
+ gfx::Insets MainAxisOuterMargin() const; |
+ |
+ // Returns the maximum margin along the cross axis from all views as insets. |
+ gfx::Insets CrossAxisMaxViewMargin() const; |
+ |
+ // Adjusts the main axis for |rect| by collapsing the left or top margin of |
+ // the first view with corresponding side of |inside_border_insets_| and the |
+ // right or bottom margin of the last view with the corresponding side of |
+ // |inside_border_insets_|. |
+ void AdjustMainAxisForMargin(gfx::Rect* rect) const; |
+ |
+ // Adjust the cross axis for |rect| using the appropriate sides of |
+ // |inside_border_insets_|. |
+ void AdjustCrossAxisForInsets(gfx::Rect* rect) const; |
// Returns the cross axis size for the given view. |
- int CrossAxisSizeForView(const View* view) const; |
+ int CrossAxisSizeForView(const ViewWrapper& view) const; |
+ |
+ // Returns the total margin width for the given view or 0 when |
+ // collapse_margins_spacing_ is true. |
+ int CrossAxisMarginSizeForView(const ViewWrapper& view) const; |
+ |
+ // Returns the Top or Left size of the margin for the given view or 0 when |
+ // collapse_margins_spacing_ is true. |
+ int CrossAxisLeadingMarginForView(const ViewWrapper& view) const; |
+ |
+ // Adjust the cross axis for |rect| using the given leading and trailing |
+ // values. |
+ void InsetCrossAxis(gfx::Rect* rect, int leading, int trailing) const; |
// The preferred size for the dialog given the width of the child area. |
gfx::Size GetPreferredSizeForChildWidth(const View* host, |
@@ -139,6 +279,16 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
// child views. |
gfx::Size NonChildSize(const View* host) const; |
+ // The next visible view at > index. If no other views are visible, return |
+ // nullptr. |
+ View* NextVisibleView(int index) const; |
+ |
+ // Return the first visible view in the host or nullptr if none are visible. |
+ View* FirstVisibleView() const; |
+ |
+ // Return the last visible view in the host or nullptr if none are visible. |
+ View* LastVisibleView() const; |
+ |
const Orientation orientation_; |
// Spacing between child views and host view border. |
@@ -156,7 +306,7 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
CrossAxisAlignment cross_axis_alignment_; |
// A map of views to their flex weights. |
- std::map<const View*, int> flex_map_; |
+ FlexMap flex_map_; |
// The flex weight for views if none is set. Defaults to 0. |
int default_flex_; |
@@ -164,6 +314,9 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager { |
// The minimum cross axis size for the layout. |
int minimum_cross_axis_size_; |
+ // Adjacent view margins and spacing should be collapsed. |
+ const bool collapse_margins_spacing_; |
+ |
// The view that this BoxLayout is managing the layout for. |
views::View* host_; |