File: pinned_toolbar_actions_container_layout.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (173 lines) | stat: -rw-r--r-- 6,887 bytes parent folder | download | duplicates (5)
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
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_layout.h"

#include "base/containers/adapters.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/view_class_properties.h"

views::ProposedLayout
PinnedToolbarActionsContainerLayout::CalculateProposedLayout(
    const views::SizeBounds& size_bounds) const {
  views::ProposedLayout layout;

  const bool size_bounded = size_bounds.is_fully_bounded();
  int remaining_width =
      size_bounded ? (size_bounds.width().value() - interior_margin_.width())
                   : 0;
  bool has_found_button_forced_visible = false;
  int mid_priority_width = 0;
  bool divider_space_preallocated = false;
  bool divider_included_for_mid_priority = false;

  // 1. Allocate space for forced visible views and calculate additional space
  // needed for medium priority views.
  if (size_bounded) {
    for (views::View* child : host_view()->children()) {
      if (!IsChildIncludedInLayout(child)) {
        continue;
      }
      const PinnedToolbarActionFlexPriority priority =
          static_cast<PinnedToolbarActionFlexPriority>(
              child->GetProperty(kToolbarButtonFlexPriorityKey));
      gfx::Size preferred_size = child->GetPreferredSize();
      preferred_size.Enlarge(child->GetProperty(views::kMarginsKey)->width(),
                             0);

      // Include forced visible views.
      if (priority == PinnedToolbarActionFlexPriority::kHigh) {
        has_found_button_forced_visible = true;
        remaining_width -= preferred_size.width();
      }
      // Track the total width of items with medium flex priority.
      if (views::Button::AsButton(child) &&
          priority == PinnedToolbarActionFlexPriority::kMedium) {
        mid_priority_width += preferred_size.width();
      }
      // Include the divider if any previous buttons are forced visible.
      if (!views::Button::AsButton(child)) {
        if (has_found_button_forced_visible) {
          divider_space_preallocated = true;
          remaining_width -= preferred_size.width();
        } else if (mid_priority_width > 0) {
          divider_included_for_mid_priority = true;
          mid_priority_width += preferred_size.width();
        }
      }
    }
  }

  // 2. Check if all medium priority items will fit in the remaining space. If
  // so, allocate space for them in the remaining width.
  const bool fits_all_medium_priority =
      !size_bounded || (remaining_width - mid_priority_width > 0);
  divider_space_preallocated =
      divider_space_preallocated ||
      (fits_all_medium_priority && divider_included_for_mid_priority);
  if (size_bounded && fits_all_medium_priority) {
    remaining_width -= mid_priority_width;
  }

  // 3. Allocate space for remaining views, and get their indices. The divider
  // should only be included if buttons after it should be included.
  std::vector<size_t> visible_child_indices;
  size_t index = host_view()->children().size() - 1;
  size_t divider_index = 0;
  int divider_width = 0;
  for (const auto& i : base::Reversed(host_view()->children())) {
    if (!IsChildIncludedInLayout(i)) {
      index--;
      continue;
    }
    // If the next child is the divider, skip it. It only is included in the
    // layout if one of the following children is visible.
    if (!views::Button::AsButton(i)) {
      divider_index = index;
      divider_width = i->GetPreferredSize().width() +
                      i->GetProperty(views::kMarginsKey)->width();
      index--;
      continue;
    }
    // Get the preferred size and include the divider width if this view is
    // causing the divider to need to be shown.
    const int margin_width = i->GetProperty(views::kMarginsKey)->width();
    gfx::Size preferred_size = i->GetPreferredSize();
    preferred_size.Enlarge(margin_width, 0);
    if (divider_index > index && !divider_space_preallocated) {
      preferred_size.Enlarge(divider_width, 0);
    }

    const PinnedToolbarActionFlexPriority priority =
        static_cast<PinnedToolbarActionFlexPriority>(
            i->GetProperty(kToolbarButtonFlexPriorityKey));
    const bool has_preallocated_space_in_layout =
        priority == PinnedToolbarActionFlexPriority::kHigh ||
        (fits_all_medium_priority &&
         priority == PinnedToolbarActionFlexPriority::kMedium);
    const bool fits_in_remaining_space =
        remaining_width >= preferred_size.width();
    const bool should_take_remaining_space =
        fits_all_medium_priority ||
        priority == PinnedToolbarActionFlexPriority::kMedium;

    // Determine whether the child should be visible in the layout and add it to
    // |visible_child_indices| if so.
    if (has_preallocated_space_in_layout ||
        (!size_bounded ||
         (fits_in_remaining_space && should_take_remaining_space))) {
      // Include the divider if necessary.
      if (divider_index != 0) {
        visible_child_indices.push_back(divider_index);
        divider_index = 0;
      }
      if (has_preallocated_space_in_layout) {
        visible_child_indices.push_back(index);
      } else {
        visible_child_indices.push_back(index);
        if (size_bounded) {
          remaining_width -= preferred_size.width();
        }
      }
    }
    index--;
  }

  // 4. Create layout based on prior calculations.
  int total_width = interior_margin_.width();
  int left = interior_margin_.left();
  index = 0;
  const int height = GetLayoutConstant(LayoutConstant::TOOLBAR_BUTTON_HEIGHT);
  for (auto view : host_view()->children()) {
    if (visible_child_indices.size() && index == visible_child_indices.back()) {
      const gfx::Size preferred_size = view->GetPreferredSize();
      const int y = (height - preferred_size.height()) / 2;
      left += view->GetProperty(views::kMarginsKey)->left();
      layout.child_layouts.emplace_back(views::ChildLayout{
          view, true,
          gfx::Rect(left, y, preferred_size.width(), preferred_size.height())});
      left += preferred_size.width() +
              view->GetProperty(views::kMarginsKey)->right();
      total_width += preferred_size.width() +
                     view->GetProperty(views::kMarginsKey)->width();
      visible_child_indices.pop_back();
    } else {
      layout.child_layouts.emplace_back(views::ChildLayout{view, false});
    }
    index++;
  }

  layout.host_size = gfx::Size(total_width, height);
  return layout;
}

void PinnedToolbarActionsContainerLayout::SetInteriorMargin(
    const gfx::Insets& interior_margin) {
  if (interior_margin_ != interior_margin) {
    interior_margin_ = interior_margin;
    InvalidateHost(true);
  }
}