1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/views/location_bar/location_bar_layout.h" 6 7 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 8 #include "ui/gfx/rect.h" 9 #include "ui/views/view.h" 10 11 12 // Description of a decoration to be added inside the location bar, either to 13 // the left or to the right. 14 struct LocationBarDecoration { 15 LocationBarDecoration(int y, 16 int height, 17 bool auto_collapse, 18 double max_fraction, 19 int edge_item_padding, 20 int item_padding, 21 int builtin_padding, 22 views::View* view); 23 24 // The y position of the view inside its parent. 25 int y; 26 27 // The height of the view. 28 int height; 29 30 // True means that, if there is not enough available space in the location 31 // bar, the view will reduce its width either to its minimal width or to zero 32 // (making it invisible), whichever fits. If true, |max_fraction| must be 0. 33 bool auto_collapse; 34 35 // Used for resizeable decorations, indicates the maximum fraction of the 36 // location bar that can be taken by this decoration, 0 for non-resizable 37 // decorations. If non-zero, |auto_collapse| must be false. 38 double max_fraction; 39 40 // Padding to use if the decoration is the first element next to the edge. 41 int edge_item_padding; 42 43 // Padding to use if the decoration follows another decoration. 44 int item_padding; 45 46 // Padding built into the decoration and that should be removed, on 47 // both sides, during layout. 48 int builtin_padding; 49 50 views::View* view; 51 52 // The width computed by the layout process. 53 double computed_width; 54 }; 55 56 LocationBarDecoration::LocationBarDecoration(int y, 57 int height, 58 bool auto_collapse, 59 double max_fraction, 60 int edge_item_padding, 61 int item_padding, 62 int builtin_padding, 63 views::View* view) 64 : y(y), 65 height(height), 66 auto_collapse(auto_collapse), 67 max_fraction(max_fraction), 68 edge_item_padding(edge_item_padding), 69 item_padding(item_padding), 70 builtin_padding(builtin_padding), 71 view(view), 72 computed_width(0) { 73 DCHECK((max_fraction == 0.0) || (!auto_collapse && (max_fraction > 0.0))); 74 } 75 76 77 // LocationBarLayout --------------------------------------------------------- 78 79 LocationBarLayout::LocationBarLayout(Position position, int item_edit_padding) 80 : position_(position), 81 item_edit_padding_(item_edit_padding) { 82 } 83 84 85 LocationBarLayout::~LocationBarLayout() { 86 } 87 88 void LocationBarLayout::AddDecoration(int y, 89 int height, 90 bool auto_collapse, 91 double max_fraction, 92 int edge_item_padding, 93 int item_padding, 94 int builtin_padding, 95 views::View* view) { 96 decorations_.push_back(new LocationBarDecoration( 97 y, height, auto_collapse, max_fraction, edge_item_padding, item_padding, 98 builtin_padding, view)); 99 } 100 101 void LocationBarLayout::AddDecoration(int y, 102 int height, 103 int builtin_padding, 104 views::View* view) { 105 decorations_.push_back(new LocationBarDecoration( 106 y, height, false, 0, LocationBarView::GetItemPadding(), 107 LocationBarView::GetItemPadding(), builtin_padding, view)); 108 } 109 110 void LocationBarLayout::LayoutPass1(int* entry_width) { 111 bool first_item = true; 112 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 113 ++i) { 114 // Autocollapsing decorations are ignored in this pass. 115 if (!(*i)->auto_collapse) { 116 *entry_width -= -2 * (*i)->builtin_padding + 117 (first_item ? (*i)->edge_item_padding : (*i)->item_padding); 118 } 119 first_item = false; 120 // Resizing decorations are ignored in this pass. 121 if (!(*i)->auto_collapse && ((*i)->max_fraction == 0.0)) { 122 (*i)->computed_width = (*i)->view->GetPreferredSize().width(); 123 *entry_width -= (*i)->computed_width; 124 } 125 } 126 *entry_width -= item_edit_padding_; 127 } 128 129 void LocationBarLayout::LayoutPass2(int *entry_width) { 130 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 131 ++i) { 132 if ((*i)->max_fraction > 0.0) { 133 int max_width = static_cast<int>(*entry_width * (*i)->max_fraction); 134 (*i)->computed_width = 135 std::min((*i)->view->GetPreferredSize().width(), 136 std::max((*i)->view->GetMinimumSize().width(), max_width)); 137 *entry_width -= (*i)->computed_width; 138 } 139 } 140 } 141 142 void LocationBarLayout::LayoutPass3(gfx::Rect* bounds, int* available_width) { 143 bool first_visible = true; 144 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 145 ++i) { 146 // Collapse decorations if needed. 147 if ((*i)->auto_collapse) { 148 int padding = -2 * (*i)->builtin_padding + 149 (first_visible ? (*i)->edge_item_padding : (*i)->item_padding); 150 // Try preferred size, if it fails try minimum size, if it fails collapse. 151 (*i)->computed_width = (*i)->view->GetPreferredSize().width(); 152 if ((*i)->computed_width + padding > *available_width) 153 (*i)->computed_width = (*i)->view->GetMinimumSize().width(); 154 if ((*i)->computed_width + padding > *available_width) { 155 (*i)->computed_width = 0; 156 (*i)->view->SetVisible(false); 157 } else { 158 (*i)->view->SetVisible(true); 159 (*available_width) -= (*i)->computed_width + padding; 160 } 161 } else { 162 (*i)->view->SetVisible(true); 163 } 164 165 // Layout visible decorations. 166 if (!(*i)->view->visible()) 167 continue; 168 int padding = -(*i)->builtin_padding + 169 (first_visible ? (*i)->edge_item_padding : (*i)->item_padding); 170 first_visible = false; 171 int x = (position_ == LEFT_EDGE) ? (bounds->x() + padding) : 172 (bounds->right() - padding - (*i)->computed_width); 173 (*i)->view->SetBounds(x, (*i)->y, (*i)->computed_width, (*i)->height); 174 bounds->set_width(bounds->width() - padding - (*i)->computed_width + 175 (*i)->builtin_padding); 176 if (position_ == LEFT_EDGE) { 177 bounds->set_x( 178 bounds->x() + padding + (*i)->computed_width - (*i)->builtin_padding); 179 } 180 } 181 bounds->set_width(bounds->width() - item_edit_padding_); 182 if (position_ == LEFT_EDGE) 183 bounds->set_x(bounds->x() + item_edit_padding_); 184 } 185