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 views::View* view); 22 23 // The y position of the view inside its parent. 24 int y; 25 26 // The height of the view. 27 int height; 28 29 // True means that, if there is not enough available space in the location 30 // bar, the view will reduce its width either to its minimal width or to zero 31 // (making it invisible), whichever fits. If true, |max_fraction| must be 0. 32 bool auto_collapse; 33 34 // Used for resizeable decorations, indicates the maximum fraction of the 35 // location bar that can be taken by this decoration, 0 for non-resizable 36 // decorations. If non-zero, |auto_collapse| must be false. 37 double max_fraction; 38 39 // Padding to use if the decoration is the first element next to the edge. 40 int edge_item_padding; 41 42 // Padding to use if the decoration follows another decoration. 43 int item_padding; 44 45 views::View* view; 46 47 // The width computed by the layout process. 48 double computed_width; 49 }; 50 51 LocationBarDecoration::LocationBarDecoration(int y, 52 int height, 53 bool auto_collapse, 54 double max_fraction, 55 int edge_item_padding, 56 int item_padding, 57 views::View* view) 58 : y(y), 59 height(height), 60 auto_collapse(auto_collapse), 61 max_fraction(max_fraction), 62 edge_item_padding(edge_item_padding), 63 item_padding(item_padding), 64 view(view), 65 computed_width(0) { 66 DCHECK((max_fraction == 0.0) || (!auto_collapse && (max_fraction > 0.0))); 67 } 68 69 70 // LocationBarLayout --------------------------------------------------------- 71 72 LocationBarLayout::LocationBarLayout(Position position, int item_edit_padding) 73 : position_(position), 74 item_edit_padding_(item_edit_padding) { 75 } 76 77 78 LocationBarLayout::~LocationBarLayout() { 79 } 80 81 void LocationBarLayout::AddDecoration(int y, 82 int height, 83 bool auto_collapse, 84 double max_fraction, 85 int edge_item_padding, 86 int item_padding, 87 views::View* view) { 88 decorations_.push_back(new LocationBarDecoration( 89 y, height, auto_collapse, max_fraction, edge_item_padding, item_padding, 90 view)); 91 } 92 93 void LocationBarLayout::AddDecoration(int y, 94 int height, 95 views::View* view) { 96 decorations_.push_back(new LocationBarDecoration( 97 y, height, false, 0, LocationBarView::kItemPadding, 98 LocationBarView::kItemPadding, view)); 99 } 100 101 void LocationBarLayout::LayoutPass1(int* entry_width) { 102 bool first_item = true; 103 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 104 ++i) { 105 // Autocollapsing decorations are ignored in this pass. 106 if (!(*i)->auto_collapse) { 107 *entry_width -= 108 (first_item ? (*i)->edge_item_padding : (*i)->item_padding); 109 } 110 first_item = false; 111 // Resizing decorations are ignored in this pass. 112 if (!(*i)->auto_collapse && ((*i)->max_fraction == 0.0)) { 113 (*i)->computed_width = (*i)->view->GetPreferredSize().width(); 114 *entry_width -= (*i)->computed_width; 115 } 116 } 117 *entry_width -= item_edit_padding_; 118 } 119 120 void LocationBarLayout::LayoutPass2(int *entry_width) { 121 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 122 ++i) { 123 if ((*i)->max_fraction > 0.0) { 124 int max_width = static_cast<int>(*entry_width * (*i)->max_fraction); 125 (*i)->computed_width = 126 std::min((*i)->view->GetPreferredSize().width(), 127 std::max((*i)->view->GetMinimumSize().width(), max_width)); 128 *entry_width -= (*i)->computed_width; 129 } 130 } 131 } 132 133 void LocationBarLayout::LayoutPass3(gfx::Rect* bounds, int* available_width) { 134 bool first_visible = true; 135 for (Decorations::iterator i(decorations_.begin()); i != decorations_.end(); 136 ++i) { 137 // Collapse decorations if needed. 138 if ((*i)->auto_collapse) { 139 int padding = 140 (first_visible ? (*i)->edge_item_padding : (*i)->item_padding); 141 // Try preferred size, if it fails try minimum size, if it fails collapse. 142 (*i)->computed_width = (*i)->view->GetPreferredSize().width(); 143 if ((*i)->computed_width + padding > *available_width) 144 (*i)->computed_width = (*i)->view->GetMinimumSize().width(); 145 if ((*i)->computed_width + padding > *available_width) { 146 (*i)->computed_width = 0; 147 (*i)->view->SetVisible(false); 148 } else { 149 (*i)->view->SetVisible(true); 150 (*available_width) -= (*i)->computed_width + padding; 151 } 152 } else { 153 (*i)->view->SetVisible(true); 154 } 155 156 // Layout visible decorations. 157 if (!(*i)->view->visible()) 158 continue; 159 int padding = 160 (first_visible ? (*i)->edge_item_padding : (*i)->item_padding); 161 first_visible = false; 162 int x = (position_ == LEFT_EDGE) ? (bounds->x() + padding) : 163 (bounds->right() - padding - (*i)->computed_width); 164 (*i)->view->SetBounds(x, (*i)->y, (*i)->computed_width, (*i)->height); 165 bounds->set_width(bounds->width() - padding - (*i)->computed_width); 166 if (position_ == LEFT_EDGE) 167 bounds->set_x(bounds->x() + padding + (*i)->computed_width); 168 } 169 bounds->set_width(bounds->width() - item_edit_padding_); 170 if (position_ == LEFT_EDGE) 171 bounds->set_x(bounds->x() + item_edit_padding_); 172 } 173