File: box_layout.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (261 lines) | stat: -rw-r--r-- 9,735 bytes parent folder | download | duplicates (8)
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_