1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_LAYOUT_BOX_LAYOUT_H_
#define UI_VIEWS_LAYOUT_BOX_LAYOUT_H_
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/layout/layout_manager_base.h"
#include "ui/views/layout/layout_types.h"
#include "ui/views/layout/normalized_geometry.h"
#include "ui/views/view.h"
namespace views {
class VIEWS_EXPORT BoxLayoutFlexSpecification {
public:
BoxLayoutFlexSpecification();
~BoxLayoutFlexSpecification();
// Makes a copy of this specification with a different weight.
BoxLayoutFlexSpecification WithWeight(int weight) const;
// Whether to use minimum values to make copies of this specification.
BoxLayoutFlexSpecification UseMinSize(bool use_min_size) const;
int weight() const { return weight_; }
bool use_min_size() const { return use_min_size_; }
private:
int weight_ = 1;
bool use_min_size_ = false;
};
// A Layout manager that arranges child views vertically or horizontally in a
// side-by-side fashion with spacing around and between the child views. The
// child views are always sized according to their preferred size. If the
// host's bounds provide insufficient space, child views will be clamped.
// Excess space will not be distributed.
class VIEWS_EXPORT BoxLayout : public LayoutManagerBase {
public:
using Orientation = LayoutOrientation;
// This specifies that the start/center/end of the collective child views is
// aligned with the start/center/end of the host view. e.g. a horizontal
// layout of MainAxisAlignment::kEnd will result in the child views being
// right-aligned.
using MainAxisAlignment = LayoutAlignment;
// This specifies where along the cross axis the children should be laid out.
// e.g. a horizontal layout of kEnd will result in the child views being
// bottom-aligned.
using CrossAxisAlignment = LayoutAlignment;
// Use |inside_border_insets| to add additional space between the child
// view area and the host view border. |between_child_spacing| controls the
// space in between child views. Use view->SetProperty(kMarginsKey,
// 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 based on the max of the two values. For the
// cross axis, |collapse_margins_spacing| will collapse to the max of
// inside_border_xxxxx_spacing and the corresponding margin edge 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
// --------------------
//
explicit BoxLayout(Orientation orientation = Orientation::kHorizontal,
const gfx::Insets& inside_border_insets = gfx::Insets(),
int between_child_spacing = 0,
bool collapse_margins_spacing = false);
~BoxLayout() override;
void SetOrientation(Orientation orientation);
Orientation GetOrientation() const;
// TODO(tluk): These class member setters should likely be calling
// LayoutManager::InvalidateLayout() .
void set_main_axis_alignment(MainAxisAlignment main_axis_alignment);
MainAxisAlignment main_axis_alignment() const { return main_axis_alignment_; }
void set_cross_axis_alignment(CrossAxisAlignment cross_axis_alignment);
CrossAxisAlignment cross_axis_alignment() const {
return cross_axis_alignment_;
}
void set_inside_border_insets(const gfx::Insets& insets);
const gfx::Insets& inside_border_insets() const {
return inside_border_insets_;
}
void set_minimum_cross_axis_size(int size) {
minimum_cross_axis_size_ = size;
}
int minimum_cross_axis_size() const { return minimum_cross_axis_size_; }
void set_between_child_spacing(int spacing) {
between_child_spacing_ = spacing;
}
int between_child_spacing() const { return between_child_spacing_; }
void SetCollapseMarginsSpacing(bool collapse_margins_spacing);
bool GetCollapseMarginsSpacing() const;
// Sets the flex weight for the given |view|. Using the preferred size as
// the basis, free space along the main axis is distributed to views in the
// ratio of their flex weights. Similarly, if the views will overflow the
// parent, space is subtracted in these ratios.
// If true is passed in for |use_min_size|, the given view's minimum size
// is then obtained from calling View::GetMinimumSize(). This will be the
// minimum allowed size for the view along the main axis. False
// for |use_min_size| (the default) will allow the |view| to be resized to a
// minimum size of 0.
//
// A flex of 0 means this view is not resized. Flex values must not be
// negative.
void SetFlexForView(const View* view, int flex, bool use_min_size = false);
// Clears the flex for the given |view|, causing it to use the default
// flex.
void ClearFlexForView(const View* view);
// Sets the flex for views to use when none is specified.
void SetDefaultFlex(int default_flex);
int GetDefaultFlex() const;
protected:
// Overridden from views::LayoutManager:
ProposedLayout CalculateProposedLayout(
const SizeBounds& size_bounds) const override;
private:
struct BoxLayoutData;
// Returns the flex for the specified |view|.
int GetFlexForView(const View* view) const;
// Returns the minimum size for the specified |view|.
int GetMinimumSizeForView(const View* view) const;
// Update `BoxChildData::margins` to account for the option to collapse
// margin spacing.
void UpdateChildMarginsIfCollapseMarginsSpacing(BoxLayoutData& data) const;
// Returns the preferred size of the current view under `size_bounds`.
gfx::Size GetPreferredSizeForView(
const View* view,
const NormalizedSizeBounds& size_bounds) const;
// Ensure that the vertical axis size of the view is no less than
// minimum_cross_axis_size_.
void EnsureCrossSize(BoxLayoutData& data) const;
// Data required to initialize the layout, including filtering views that do
// not participate in the layout and calculating the maximum leading and
// trailing margin.
void InitializeChildData(BoxLayoutData& data) const;
// Calculate the maximum child width, only used in vertical layout when no
// main view bounds are provided.
SizeBound CalculateMaxChildWidth(BoxLayoutData& data) const;
// Calculate the preferred size of each subview by assuming that it takes the
// entire available space.
void CalculatePreferredSize(const SizeBounds& size_bounds,
BoxLayoutData& data) const;
// Calculate the total size of host_view. If no main view bounds are provided,
// this will be the total size of the content
void CalculatePreferredTotalSize(BoxLayoutData& data) const;
// Update and calculate the actual positions of all subviews based on flex
// rules.
void UpdateFlexLayout(const NormalizedSizeBounds& bounds,
BoxLayoutData& data) const;
// Get actual main size and update preferred size if needed.
// The actual main size is the original preferred size plus
// `current_padding`. Recalculate the preferred size if the
// size is shrunk.
int GetActualMainSizeAndUpdateChildPreferredSizeIfNeeded(
const NormalizedSizeBounds& bounds,
BoxLayoutData& data,
size_t index,
int current_padding,
SizeBound cross_axis_size) const;
// Apply alignment rules to the subview, this will crop the subview when it
// exceeds the bounds.
void CalculateChildBounds(const SizeBounds& size_bounds,
BoxLayoutData& data) const;
Orientation orientation_;
// Spacing between child views and host view border.
gfx::Insets inside_border_insets_;
// Spacing to put in between child views.
int between_child_spacing_;
// The alignment of children in the main axis. This is
// MainAxisAlignment::kStart by default.
MainAxisAlignment main_axis_alignment_ = MainAxisAlignment::kStart;
// The alignment of children in the cross axis. This is
// kStretch by default.
CrossAxisAlignment cross_axis_alignment_ = CrossAxisAlignment::kStretch;
// The flex weight for views if none is set. Defaults to 0.
int default_flex_ = 0;
// The minimum cross axis size for the layout.
int minimum_cross_axis_size_ = 0;
// Adjacent view margins and spacing should be collapsed.
bool collapse_margins_spacing_;
};
} // namespace views
#endif // UI_VIEWS_LAYOUT_BOX_LAYOUT_H_
|