Home | History | Annotate | Download | only in layout
      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 "ui/views/layout/grid_layout.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "base/stl_util.h"
     11 #include "ui/gfx/insets.h"
     12 #include "ui/views/layout/layout_constants.h"
     13 #include "ui/views/view.h"
     14 #include "ui/views/window/dialog_delegate.h"
     15 
     16 namespace views {
     17 
     18 // LayoutElement ------------------------------------------------------
     19 
     20 // A LayoutElement has a size and location along one axis. It contains
     21 // methods that are used along both axis.
     22 class LayoutElement {
     23  public:
     24   // Invokes ResetSize on all the layout elements.
     25   template <class T>
     26   static void ResetSizes(std::vector<T*>* elements) {
     27     // Reset the layout width of each column.
     28     for (typename std::vector<T*>::iterator i = elements->begin();
     29          i != elements->end(); ++i) {
     30       (*i)->ResetSize();
     31     }
     32   }
     33 
     34   // Sets the location of each element to be the sum of the sizes of the
     35   // preceding elements.
     36   template <class T>
     37   static void CalculateLocationsFromSize(std::vector<T*>* elements) {
     38     // Reset the layout width of each column.
     39     int location = 0;
     40     for (typename std::vector<T*>::iterator i = elements->begin();
     41          i != elements->end(); ++i) {
     42       (*i)->SetLocation(location);
     43       location += (*i)->Size();
     44     }
     45   }
     46 
     47   // Distributes delta among the resizable elements.
     48   // Each resizable element is given ResizePercent / total_percent * delta
     49   // pixels extra of space.
     50   template <class T>
     51   static void DistributeDelta(int delta, std::vector<T*>* elements) {
     52     if (delta == 0)
     53       return;
     54 
     55     float total_percent = 0;
     56     int resize_count = 0;
     57     for (typename std::vector<T*>::iterator i = elements->begin();
     58          i != elements->end(); ++i) {
     59       total_percent += (*i)->ResizePercent();
     60       if ((*i)->ResizePercent() > 0)
     61         resize_count++;
     62     }
     63     if (total_percent == 0) {
     64       // None of the elements are resizable, return.
     65       return;
     66     }
     67     int remaining = delta;
     68     int resized = resize_count;
     69     for (typename std::vector<T*>::iterator i = elements->begin();
     70          i != elements->end(); ++i) {
     71       T* element = *i;
     72       if (element->ResizePercent() > 0) {
     73         int to_give;
     74         if (--resized == 0) {
     75           to_give = remaining;
     76         } else {
     77           to_give = static_cast<int>(delta *
     78                                     (element->resize_percent_ / total_percent));
     79           remaining -= to_give;
     80         }
     81         element->SetSize(element->Size() + to_give);
     82       }
     83     }
     84   }
     85 
     86   // Returns the sum of the size of the elements from start to start + length.
     87   template <class T>
     88   static int TotalSize(int start, int length, std::vector<T*>* elements) {
     89     DCHECK(start >= 0 && length > 0 &&
     90            start + length <= static_cast<int>(elements->size()));
     91     int size = 0;
     92     for (int i = start, max = start + length; i < max; ++i) {
     93       size += (*elements)[i]->Size();
     94     }
     95     return size;
     96   }
     97 
     98   explicit LayoutElement(float resize_percent)
     99       : resize_percent_(resize_percent) {
    100     DCHECK(resize_percent >= 0);
    101   }
    102 
    103   virtual ~LayoutElement() {}
    104 
    105   void SetLocation(int location) {
    106     location_ = location;
    107   }
    108 
    109   int Location() {
    110     return location_;
    111   }
    112 
    113   // Adjusts the size of this LayoutElement to be the max of the current size
    114   // and the specified size.
    115   virtual void AdjustSize(int size) {
    116     size_ = std::max(size_, size);
    117   }
    118 
    119   // Resets the size to the initial size. This sets the size to 0, but
    120   // subclasses that have a different initial size should override.
    121   virtual void ResetSize() {
    122     SetSize(0);
    123   }
    124 
    125   void SetSize(int size) {
    126     size_ = size;
    127   }
    128 
    129   int Size() {
    130     return size_;
    131   }
    132 
    133   void SetResizePercent(float percent) {
    134     resize_percent_ = percent;
    135   }
    136 
    137   float ResizePercent() {
    138     return resize_percent_;
    139   }
    140 
    141   bool IsResizable() {
    142     return resize_percent_ > 0;
    143   }
    144 
    145  private:
    146   float resize_percent_;
    147   int location_;
    148   int size_;
    149 
    150   DISALLOW_COPY_AND_ASSIGN(LayoutElement);
    151 };
    152 
    153 // Column -------------------------------------------------------------
    154 
    155 // As the name implies, this represents a Column. Column contains default
    156 // values for views originating in this column.
    157 class Column : public LayoutElement {
    158  public:
    159   Column(GridLayout::Alignment h_align,
    160          GridLayout::Alignment v_align,
    161          float resize_percent,
    162          GridLayout::SizeType size_type,
    163          int fixed_width,
    164          int min_width,
    165          bool is_padding)
    166     : LayoutElement(resize_percent),
    167       h_align_(h_align),
    168       v_align_(v_align),
    169       size_type_(size_type),
    170       same_size_column_(-1),
    171       fixed_width_(fixed_width),
    172       min_width_(min_width),
    173       is_padding_(is_padding),
    174       master_column_(NULL) {}
    175 
    176   virtual ~Column() {}
    177 
    178   GridLayout::Alignment h_align() { return h_align_; }
    179   GridLayout::Alignment v_align() { return v_align_; }
    180 
    181   virtual void ResetSize() OVERRIDE;
    182 
    183  private:
    184   friend class ColumnSet;
    185   friend class GridLayout;
    186 
    187   Column* GetLastMasterColumn();
    188 
    189   // Determines the max size of all linked columns, and sets each column
    190   // to that size. This should only be used for the master column.
    191   void UnifySameSizedColumnSizes();
    192 
    193   virtual void AdjustSize(int size) OVERRIDE;
    194 
    195   const GridLayout::Alignment h_align_;
    196   const GridLayout::Alignment v_align_;
    197   const GridLayout::SizeType size_type_;
    198   int same_size_column_;
    199   const int fixed_width_;
    200   const int min_width_;
    201 
    202   const bool is_padding_;
    203 
    204   // If multiple columns have their sizes linked, one is the
    205   // master column. The master column is identified by the
    206   // master_column field being equal to itself. The master columns
    207   // same_size_columns field contains the set of Columns with the
    208   // the same size. Columns who are linked to other columns, but
    209   // are not the master column have their master_column pointing to
    210   // one of the other linked columns. Use the method GetLastMasterColumn
    211   // to resolve the true master column.
    212   std::vector<Column*> same_size_columns_;
    213   Column* master_column_;
    214 
    215   DISALLOW_COPY_AND_ASSIGN(Column);
    216 };
    217 
    218 void Column::ResetSize() {
    219   if (size_type_ == GridLayout::FIXED) {
    220     SetSize(fixed_width_);
    221   } else {
    222     SetSize(min_width_);
    223   }
    224 }
    225 
    226 Column* Column::GetLastMasterColumn() {
    227   if (master_column_ == NULL) {
    228     return NULL;
    229   }
    230   if (master_column_ == this) {
    231     return this;
    232   }
    233   return master_column_->GetLastMasterColumn();
    234 }
    235 
    236 void Column::UnifySameSizedColumnSizes() {
    237   DCHECK(master_column_ == this);
    238 
    239   // Accumulate the size first.
    240   int size = 0;
    241   for (std::vector<Column*>::iterator i = same_size_columns_.begin();
    242        i != same_size_columns_.end(); ++i) {
    243       size = std::max(size, (*i)->Size());
    244   }
    245 
    246   // Then apply it.
    247   for (std::vector<Column*>::iterator i = same_size_columns_.begin();
    248        i != same_size_columns_.end(); ++i) {
    249       (*i)->SetSize(size);
    250   }
    251 }
    252 
    253 void Column::AdjustSize(int size) {
    254   if (size_type_ == GridLayout::USE_PREF)
    255     LayoutElement::AdjustSize(size);
    256 }
    257 
    258 // Row -------------------------------------------------------------
    259 
    260 class Row : public LayoutElement {
    261  public:
    262   Row(int height, float resize_percent, ColumnSet* column_set)
    263     : LayoutElement(resize_percent),
    264       height_(height),
    265       column_set_(column_set),
    266       max_ascent_(0),
    267       max_descent_(0) {
    268   }
    269 
    270   virtual ~Row() {}
    271 
    272   virtual void ResetSize() OVERRIDE {
    273     max_ascent_ = max_descent_ = 0;
    274     SetSize(height_);
    275   }
    276 
    277   ColumnSet* column_set() {
    278     return column_set_;
    279   }
    280 
    281   // Adjusts the size to accomodate the specified ascent/descent.
    282   void AdjustSizeForBaseline(int ascent, int descent) {
    283     max_ascent_ = std::max(ascent, max_ascent_);
    284     max_descent_ = std::max(descent, max_descent_);
    285     AdjustSize(max_ascent_ + max_descent_);
    286   }
    287 
    288   int max_ascent() const {
    289     return max_ascent_;
    290   }
    291 
    292   int max_descent() const {
    293     return max_descent_;
    294   }
    295 
    296  private:
    297   const int height_;
    298   // The column set used for this row; null for padding rows.
    299   ColumnSet* column_set_;
    300 
    301   int max_ascent_;
    302   int max_descent_;
    303 
    304   DISALLOW_COPY_AND_ASSIGN(Row);
    305 };
    306 
    307 // ViewState -------------------------------------------------------------
    308 
    309 // Identifies the location in the grid of a particular view, along with
    310 // placement information and size information.
    311 struct ViewState {
    312   ViewState(ColumnSet* column_set, View* view, int start_col, int start_row,
    313             int col_span, int row_span, GridLayout::Alignment h_align,
    314             GridLayout::Alignment v_align, int pref_width, int pref_height)
    315       : column_set(column_set),
    316         view(view),
    317         start_col(start_col),
    318         start_row(start_row),
    319         col_span(col_span),
    320         row_span(row_span),
    321         h_align(h_align),
    322         v_align(v_align),
    323         pref_width_fixed(pref_width > 0),
    324         pref_height_fixed(pref_height > 0),
    325         pref_width(pref_width),
    326         pref_height(pref_height),
    327         remaining_width(0),
    328         remaining_height(0),
    329         baseline(-1) {
    330     DCHECK(view && start_col >= 0 && start_row >= 0 && col_span > 0 &&
    331            row_span > 0 && start_col < column_set->num_columns() &&
    332            (start_col + col_span) <= column_set->num_columns());
    333   }
    334 
    335   ColumnSet* const column_set;
    336   View* const view;
    337   const int start_col;
    338   const int start_row;
    339   const int col_span;
    340   const int row_span;
    341   const GridLayout::Alignment h_align;
    342   const GridLayout::Alignment v_align;
    343 
    344   // If true, the pref_width/pref_height were explicitly set and the view's
    345   // preferred size is ignored.
    346   const bool pref_width_fixed;
    347   const bool pref_height_fixed;
    348 
    349   // The preferred width/height. These are reset during the layout process.
    350   int pref_width;
    351   int pref_height;
    352 
    353   // Used during layout. Gives how much width/height has not yet been
    354   // distributed to the columns/rows the view is in.
    355   int remaining_width;
    356   int remaining_height;
    357 
    358   // The baseline. Only used if the view is vertically aligned along the
    359   // baseline.
    360   int baseline;
    361 };
    362 
    363 static bool CompareByColumnSpan(const ViewState* v1, const ViewState* v2) {
    364   return v1->col_span < v2->col_span;
    365 }
    366 
    367 static bool CompareByRowSpan(const ViewState* v1, const ViewState* v2) {
    368   return v1->row_span < v2->row_span;
    369 }
    370 
    371 // ColumnSet -------------------------------------------------------------
    372 
    373 ColumnSet::ColumnSet(int id) : id_(id) {
    374 }
    375 
    376 ColumnSet::~ColumnSet() {
    377   STLDeleteElements(&columns_);
    378 }
    379 
    380 void ColumnSet::AddPaddingColumn(float resize_percent, int width) {
    381   AddColumn(GridLayout::FILL, GridLayout::FILL, resize_percent,
    382             GridLayout::FIXED, width, width, true);
    383 }
    384 
    385 void ColumnSet::AddColumn(GridLayout::Alignment h_align,
    386                           GridLayout::Alignment v_align,
    387                           float resize_percent,
    388                           GridLayout::SizeType size_type,
    389                           int fixed_width,
    390                           int min_width) {
    391   AddColumn(h_align, v_align, resize_percent, size_type, fixed_width,
    392             min_width, false);
    393 }
    394 
    395 
    396 void ColumnSet::LinkColumnSizes(int first, ...) {
    397   va_list marker;
    398   va_start(marker, first);
    399   DCHECK(first >= 0 && first < num_columns());
    400   for (int last = first, next = va_arg(marker, int); next != -1;
    401        next = va_arg(marker, int)) {
    402     DCHECK(next >= 0 && next < num_columns());
    403     columns_[last]->same_size_column_ = next;
    404     last = next;
    405   }
    406   va_end(marker);
    407 }
    408 
    409 void ColumnSet::AddColumn(GridLayout::Alignment h_align,
    410                           GridLayout::Alignment v_align,
    411                           float resize_percent,
    412                           GridLayout::SizeType size_type,
    413                           int fixed_width,
    414                           int min_width,
    415                           bool is_padding) {
    416   Column* column = new Column(h_align, v_align, resize_percent, size_type,
    417                               fixed_width, min_width, is_padding);
    418   columns_.push_back(column);
    419 }
    420 
    421 void ColumnSet::AddViewState(ViewState* view_state) {
    422   // view_states are ordered by column_span (in ascending order).
    423   std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
    424                                                          view_states_.end(),
    425                                                          view_state,
    426                                                          CompareByColumnSpan);
    427   view_states_.insert(i, view_state);
    428 }
    429 
    430 void ColumnSet::CalculateMasterColumns() {
    431   for (std::vector<Column*>::iterator i = columns_.begin();
    432        i != columns_.end(); ++i) {
    433     Column* column = *i;
    434     int same_size_column_index = column->same_size_column_;
    435     if (same_size_column_index != -1) {
    436       DCHECK(same_size_column_index >= 0 &&
    437              same_size_column_index < static_cast<int>(columns_.size()));
    438       Column* master_column = column->master_column_;
    439       Column* same_size_column = columns_[same_size_column_index];
    440       Column* same_size_column_master = same_size_column->master_column_;
    441       if (master_column == NULL) {
    442         // Current column is not linked to any other column.
    443         if (same_size_column_master == NULL) {
    444           // Both columns are not linked.
    445           column->master_column_ = column;
    446           same_size_column->master_column_ = column;
    447           column->same_size_columns_.push_back(same_size_column);
    448           column->same_size_columns_.push_back(column);
    449         } else {
    450           // Column to link to is linked with other columns.
    451           // Add current column to list of linked columns in other columns
    452           // master column.
    453           same_size_column->GetLastMasterColumn()->
    454               same_size_columns_.push_back(column);
    455           // And update the master column for the current column to that
    456           // of the same sized column.
    457           column->master_column_ = same_size_column;
    458         }
    459       } else {
    460         // Current column is already linked with another column.
    461         if (same_size_column_master == NULL) {
    462           // Column to link with is not linked to any other columns.
    463           // Update it's master_column.
    464           same_size_column->master_column_ = column;
    465           // Add linked column to list of linked column.
    466           column->GetLastMasterColumn()->same_size_columns_.
    467               push_back(same_size_column);
    468         } else if (column->GetLastMasterColumn() !=
    469                    same_size_column->GetLastMasterColumn()) {
    470           // The two columns are already linked with other columns.
    471           std::vector<Column*>* same_size_columns =
    472               &(column->GetLastMasterColumn()->same_size_columns_);
    473           std::vector<Column*>* other_same_size_columns =
    474               &(same_size_column->GetLastMasterColumn()->same_size_columns_);
    475           // Add all the columns from the others master to current columns
    476           // master.
    477           same_size_columns->insert(same_size_columns->end(),
    478                                      other_same_size_columns->begin(),
    479                                      other_same_size_columns->end());
    480           // The other master is no longer a master, clear its vector of
    481           // linked columns, and reset its master_column.
    482           other_same_size_columns->clear();
    483           same_size_column->GetLastMasterColumn()->master_column_ = column;
    484         }
    485       }
    486     }
    487   }
    488   AccumulateMasterColumns();
    489 }
    490 
    491 void ColumnSet::AccumulateMasterColumns() {
    492   DCHECK(master_columns_.empty());
    493   for (std::vector<Column*>::iterator i = columns_.begin();
    494        i != columns_.end(); ++i) {
    495     Column* column = *i;
    496     Column* master_column = column->GetLastMasterColumn();
    497     if (master_column &&
    498         std::find(master_columns_.begin(), master_columns_.end(),
    499                   master_column) == master_columns_.end()) {
    500       master_columns_.push_back(master_column);
    501     }
    502     // At this point, GetLastMasterColumn may not == master_column
    503     // (may have to go through a few Columns)_. Reset master_column to
    504     // avoid hops.
    505     column->master_column_ = master_column;
    506   }
    507 }
    508 
    509 void ColumnSet::UnifySameSizedColumnSizes() {
    510   for (std::vector<Column*>::iterator i = master_columns_.begin();
    511        i != master_columns_.end(); ++i) {
    512     (*i)->UnifySameSizedColumnSizes();
    513   }
    514 }
    515 
    516 void ColumnSet::UpdateRemainingWidth(ViewState* view_state) {
    517   for (int i = view_state->start_col,
    518        max_col = view_state->start_col + view_state->col_span;
    519        i < max_col; ++i) {
    520     view_state->remaining_width -= columns_[i]->Size();
    521   }
    522 }
    523 
    524 void ColumnSet::DistributeRemainingWidth(ViewState* view_state) {
    525   // This is nearly the same as that for rows, but differs in so far as how
    526   // Rows and Columns are treated. Rows have two states, resizable or not.
    527   // Columns have three, resizable, USE_PREF or not resizable. This results
    528   // in slightly different handling for distributing unaccounted size.
    529   int width = view_state->remaining_width;
    530   if (width <= 0) {
    531     // The columns this view is in are big enough to accommodate it.
    532     return;
    533   }
    534 
    535   // Determine which columns are resizable, and which have a size type
    536   // of USE_PREF.
    537   int resizable_columns = 0;
    538   int pref_size_columns = 0;
    539   int start_col = view_state->start_col;
    540   int max_col = view_state->start_col + view_state->col_span;
    541   float total_resize = 0;
    542   for (int i = start_col; i < max_col; ++i) {
    543     if (columns_[i]->IsResizable()) {
    544       total_resize += columns_[i]->ResizePercent();
    545       resizable_columns++;
    546     } else if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
    547       pref_size_columns++;
    548     }
    549   }
    550 
    551   if (resizable_columns > 0) {
    552     // There are resizable columns, give them the remaining width. The extra
    553     // width is distributed using the resize values of each column.
    554     int remaining_width = width;
    555     for (int i = start_col, resize_i = 0; i < max_col; ++i) {
    556       if (columns_[i]->IsResizable()) {
    557         resize_i++;
    558         int delta = (resize_i == resizable_columns) ? remaining_width :
    559             static_cast<int>(width * columns_[i]->ResizePercent() /
    560                              total_resize);
    561         remaining_width -= delta;
    562         columns_[i]->SetSize(columns_[i]->Size() + delta);
    563       }
    564     }
    565   } else if (pref_size_columns > 0) {
    566     // None of the columns are resizable, distribute the width among those
    567     // that use the preferred size.
    568     int to_distribute = width / pref_size_columns;
    569     for (int i = start_col; i < max_col; ++i) {
    570       if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
    571         width -= to_distribute;
    572         if (width < to_distribute)
    573           to_distribute += width;
    574         columns_[i]->SetSize(columns_[i]->Size() + to_distribute);
    575       }
    576     }
    577   }
    578 }
    579 
    580 int ColumnSet::LayoutWidth() {
    581   int width = 0;
    582   for (std::vector<Column*>::iterator i = columns_.begin();
    583        i != columns_.end(); ++i) {
    584     width += (*i)->Size();
    585   }
    586   return width;
    587 }
    588 
    589 int ColumnSet::GetColumnWidth(int start_col, int col_span) {
    590   return LayoutElement::TotalSize(start_col, col_span, &columns_);
    591 }
    592 
    593 void ColumnSet::ResetColumnXCoordinates() {
    594   LayoutElement::CalculateLocationsFromSize(&columns_);
    595 }
    596 
    597 void ColumnSet::CalculateSize() {
    598   gfx::Size pref;
    599   // Reset the preferred and remaining sizes.
    600   for (std::vector<ViewState*>::iterator i = view_states_.begin();
    601        i != view_states_.end(); ++i) {
    602     ViewState* view_state = *i;
    603     if (!view_state->pref_width_fixed || !view_state->pref_height_fixed) {
    604       pref = view_state->view->GetPreferredSize();
    605       if (!view_state->pref_width_fixed)
    606         view_state->pref_width = pref.width();
    607       if (!view_state->pref_height_fixed)
    608         view_state->pref_height = pref.height();
    609     }
    610     view_state->remaining_width = pref.width();
    611     view_state->remaining_height = pref.height();
    612   }
    613 
    614   // Let layout element reset the sizes for us.
    615   LayoutElement::ResetSizes(&columns_);
    616 
    617   // Distribute the size of each view with a col span == 1.
    618   std::vector<ViewState*>::iterator view_state_iterator =
    619       view_states_.begin();
    620   for (; view_state_iterator != view_states_.end() &&
    621          (*view_state_iterator)->col_span == 1; ++view_state_iterator) {
    622     ViewState* view_state = *view_state_iterator;
    623     Column* column = columns_[view_state->start_col];
    624     column->AdjustSize(view_state->pref_width);
    625     view_state->remaining_width -= column->Size();
    626   }
    627 
    628   // Make sure all linked columns have the same size.
    629   UnifySameSizedColumnSizes();
    630 
    631   // Distribute the size of each view with a column span > 1.
    632   for (; view_state_iterator != view_states_.end(); ++view_state_iterator) {
    633     ViewState* view_state = *view_state_iterator;
    634 
    635     // Update the remaining_width from columns this view_state touches.
    636     UpdateRemainingWidth(view_state);
    637 
    638     // Distribute the remaining width.
    639     DistributeRemainingWidth(view_state);
    640 
    641     // Update the size of linked columns.
    642     // This may need to be combined with previous step.
    643     UnifySameSizedColumnSizes();
    644   }
    645 }
    646 
    647 void ColumnSet::Resize(int delta) {
    648   LayoutElement::DistributeDelta(delta, &columns_);
    649 }
    650 
    651 // GridLayout -------------------------------------------------------------
    652 
    653 GridLayout::GridLayout(View* host)
    654     : host_(host),
    655       calculated_master_columns_(false),
    656       remaining_row_span_(0),
    657       current_row_(-1),
    658       next_column_(0),
    659       current_row_col_set_(NULL),
    660       adding_view_(false) {
    661   DCHECK(host);
    662 }
    663 
    664 GridLayout::~GridLayout() {
    665   STLDeleteElements(&column_sets_);
    666   STLDeleteElements(&view_states_);
    667   STLDeleteElements(&rows_);
    668 }
    669 
    670 // static
    671 GridLayout* GridLayout::CreatePanel(View* host) {
    672   GridLayout* layout = new GridLayout(host);
    673   layout->SetInsets(kPanelVertMargin, kButtonHEdgeMarginNew,
    674                     kPanelVertMargin, kButtonHEdgeMarginNew);
    675   return layout;
    676 }
    677 
    678 void GridLayout::SetInsets(int top, int left, int bottom, int right) {
    679   insets_.Set(top, left, bottom, right);
    680 }
    681 
    682 void GridLayout::SetInsets(const gfx::Insets& insets) {
    683   insets_ = insets;
    684 }
    685 
    686 ColumnSet* GridLayout::AddColumnSet(int id) {
    687   DCHECK(GetColumnSet(id) == NULL);
    688   ColumnSet* column_set = new ColumnSet(id);
    689   column_sets_.push_back(column_set);
    690   return column_set;
    691 }
    692 
    693 ColumnSet* GridLayout::GetColumnSet(int id) {
    694   for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
    695        i != column_sets_.end(); ++i) {
    696     if ((*i)->id_ == id) {
    697       return *i;
    698     }
    699   }
    700   return NULL;
    701 }
    702 
    703 void GridLayout::StartRowWithPadding(float vertical_resize, int column_set_id,
    704                                      float padding_resize, int padding) {
    705   AddPaddingRow(padding_resize, padding);
    706   StartRow(vertical_resize, column_set_id);
    707 }
    708 
    709 void GridLayout::StartRow(float vertical_resize, int column_set_id) {
    710   ColumnSet* column_set = GetColumnSet(column_set_id);
    711   DCHECK(column_set);
    712   AddRow(new Row(0, vertical_resize, column_set));
    713 }
    714 
    715 void GridLayout::AddPaddingRow(float vertical_resize, int pixel_count) {
    716   AddRow(new Row(pixel_count, vertical_resize, NULL));
    717 }
    718 
    719 void GridLayout::SkipColumns(int col_count) {
    720   DCHECK(col_count > 0);
    721   next_column_ += col_count;
    722   DCHECK(current_row_col_set_ &&
    723          next_column_ <= current_row_col_set_->num_columns());
    724   SkipPaddingColumns();
    725 }
    726 
    727 void GridLayout::AddView(View* view) {
    728   AddView(view, 1, 1);
    729 }
    730 
    731 void GridLayout::AddView(View* view, int col_span, int row_span) {
    732   DCHECK(current_row_col_set_ &&
    733          next_column_ < current_row_col_set_->num_columns());
    734   Column* column = current_row_col_set_->columns_[next_column_];
    735   AddView(view, col_span, row_span, column->h_align(), column->v_align());
    736 }
    737 
    738 void GridLayout::AddView(View* view, int col_span, int row_span,
    739                          Alignment h_align, Alignment v_align) {
    740   AddView(view, col_span, row_span, h_align, v_align, 0, 0);
    741 }
    742 
    743 void GridLayout::AddView(View* view, int col_span, int row_span,
    744                          Alignment h_align, Alignment v_align,
    745                          int pref_width, int pref_height) {
    746   DCHECK(current_row_col_set_ && col_span > 0 && row_span > 0 &&
    747          (next_column_ + col_span) <= current_row_col_set_->num_columns());
    748   // We don't support baseline alignment of views spanning rows. Please add if
    749   // you need it.
    750   DCHECK(v_align != BASELINE || row_span == 1);
    751   ViewState* state =
    752       new ViewState(current_row_col_set_, view, next_column_, current_row_,
    753                     col_span, row_span, h_align, v_align, pref_width,
    754                     pref_height);
    755   AddViewState(state);
    756 }
    757 
    758 static void CalculateSize(int pref_size, GridLayout::Alignment alignment,
    759                           int* location, int* size) {
    760   if (alignment != GridLayout::FILL) {
    761     int available_size = *size;
    762     *size = std::min(*size, pref_size);
    763     switch (alignment) {
    764       case GridLayout::LEADING:
    765         // Nothing to do, location already points to start.
    766         break;
    767       case GridLayout::BASELINE:  // If we were asked to align on baseline, but
    768                                   // the view doesn't have a baseline, fall back
    769                                   // to center.
    770       case GridLayout::CENTER:
    771         *location += (available_size - *size) / 2;
    772         break;
    773       case GridLayout::TRAILING:
    774         *location = *location + available_size - *size;
    775         break;
    776       default:
    777         NOTREACHED();
    778     }
    779   }
    780 }
    781 
    782 void GridLayout::Installed(View* host) {
    783   DCHECK(host_ == host);
    784 }
    785 
    786 void GridLayout::Uninstalled(View* host) {
    787   DCHECK(host_ == host);
    788 }
    789 
    790 void GridLayout::ViewAdded(View* host, View* view) {
    791   DCHECK(host_ == host && adding_view_);
    792 }
    793 
    794 void GridLayout::ViewRemoved(View* host, View* view) {
    795   DCHECK(host_ == host);
    796 }
    797 
    798 void GridLayout::Layout(View* host) {
    799   DCHECK(host_ == host);
    800   // SizeRowsAndColumns sets the size and location of each row/column, but
    801   // not of the views.
    802   gfx::Size pref;
    803   SizeRowsAndColumns(true, host_->width(), host_->height(), &pref);
    804 
    805   // Size each view.
    806   for (std::vector<ViewState*>::iterator i = view_states_.begin();
    807        i != view_states_.end(); ++i) {
    808     ViewState* view_state = *i;
    809     ColumnSet* column_set = view_state->column_set;
    810     View* view = (*i)->view;
    811     DCHECK(view);
    812     int x = column_set->columns_[view_state->start_col]->Location() +
    813             insets_.left();
    814     int width = column_set->GetColumnWidth(view_state->start_col,
    815                                            view_state->col_span);
    816     CalculateSize(view_state->pref_width, view_state->h_align,
    817                   &x, &width);
    818     int y = rows_[view_state->start_row]->Location() + insets_.top();
    819     int height = LayoutElement::TotalSize(view_state->start_row,
    820                                           view_state->row_span, &rows_);
    821     if (view_state->v_align == BASELINE && view_state->baseline != -1) {
    822       y += rows_[view_state->start_row]->max_ascent() - view_state->baseline;
    823       height = view_state->pref_height;
    824     } else {
    825       CalculateSize(view_state->pref_height, view_state->v_align, &y, &height);
    826     }
    827     view->SetBounds(x, y, width, height);
    828   }
    829 }
    830 
    831 gfx::Size GridLayout::GetPreferredSize(const View* host) const {
    832   DCHECK(host_ == host);
    833   gfx::Size out;
    834   SizeRowsAndColumns(false, 0, 0, &out);
    835   out.SetSize(std::max(out.width(), minimum_size_.width()),
    836               std::max(out.height(), minimum_size_.height()));
    837   return out;
    838 }
    839 
    840 int GridLayout::GetPreferredHeightForWidth(const View* host, int width) const {
    841   DCHECK(host_ == host);
    842   gfx::Size pref;
    843   SizeRowsAndColumns(false, width, 0, &pref);
    844   return pref.height();
    845 }
    846 
    847 void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
    848                                     gfx::Size* pref) const {
    849   // Make sure the master columns have been calculated.
    850   CalculateMasterColumnsIfNecessary();
    851   pref->SetSize(0, 0);
    852   if (rows_.empty())
    853     return;
    854 
    855   // Calculate the preferred width of each of the columns. Some views'
    856   // preferred heights are derived from their width, as such we need to
    857   // calculate the size of the columns first.
    858   for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
    859        i != column_sets_.end(); ++i) {
    860     (*i)->CalculateSize();
    861     pref->set_width(std::max(pref->width(), (*i)->LayoutWidth()));
    862   }
    863   pref->set_width(pref->width() + insets_.width());
    864 
    865   // Go over the columns again and set them all to the size we settled for.
    866   width = width ? width : pref->width();
    867   for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
    868        i != column_sets_.end(); ++i) {
    869     // We're doing a layout, divy up any extra space.
    870     (*i)->Resize(width - (*i)->LayoutWidth() - insets_.left() -
    871                  insets_.right());
    872     // And reset the x coordinates.
    873     (*i)->ResetColumnXCoordinates();
    874   }
    875 
    876   // Reset the height of each row.
    877   LayoutElement::ResetSizes(&rows_);
    878 
    879   // Do the following:
    880   // . If the view is aligned along it's baseline, obtain the baseline from the
    881   //   view and update the rows ascent/descent.
    882   // . Reset the remaining_height of each view state.
    883   // . If the width the view will be given is different than it's pref, ask
    884   //   for the height given a particularly width.
    885   for (std::vector<ViewState*>::iterator i= view_states_.begin();
    886        i != view_states_.end() ; ++i) {
    887     ViewState* view_state = *i;
    888     view_state->remaining_height = view_state->pref_height;
    889 
    890     if (view_state->v_align == BASELINE)
    891       view_state->baseline = view_state->view->GetBaseline();
    892 
    893     if (view_state->h_align == FILL) {
    894       // The view is resizable. As the pref height may vary with the width,
    895       // ask for the pref again.
    896       int actual_width =
    897           view_state->column_set->GetColumnWidth(view_state->start_col,
    898                                                  view_state->col_span);
    899       if (actual_width != view_state->pref_width &&
    900           !view_state->pref_height_fixed) {
    901         // The width this view will get differs from its preferred. Some Views
    902         // pref height varies with its width; ask for the preferred again.
    903         view_state->pref_height =
    904             view_state->view->GetHeightForWidth(actual_width);
    905         view_state->remaining_height = view_state->pref_height;
    906       }
    907     }
    908   }
    909 
    910   // Update the height/ascent/descent of each row from the views.
    911   std::vector<ViewState*>::iterator view_states_iterator = view_states_.begin();
    912   for (; view_states_iterator != view_states_.end() &&
    913       (*view_states_iterator)->row_span == 1; ++view_states_iterator) {
    914     ViewState* view_state = *view_states_iterator;
    915     Row* row = rows_[view_state->start_row];
    916     row->AdjustSize(view_state->remaining_height);
    917     if (view_state->baseline != -1 &&
    918         view_state->baseline <= view_state->pref_height) {
    919       row->AdjustSizeForBaseline(view_state->baseline,
    920           view_state->pref_height - view_state->baseline);
    921     }
    922     view_state->remaining_height = 0;
    923   }
    924 
    925   // Distribute the height of each view with a row span > 1.
    926   for (; view_states_iterator != view_states_.end(); ++view_states_iterator) {
    927     ViewState* view_state = *view_states_iterator;
    928 
    929     // Update the remaining_width from columns this view_state touches.
    930     UpdateRemainingHeightFromRows(view_state);
    931 
    932     // Distribute the remaining height.
    933     DistributeRemainingHeight(view_state);
    934   }
    935 
    936   // Update the location of each of the rows.
    937   LayoutElement::CalculateLocationsFromSize(&rows_);
    938 
    939   // We now know the preferred height, set it here.
    940   pref->set_height(rows_[rows_.size() - 1]->Location() +
    941       rows_[rows_.size() - 1]->Size() + insets_.height());
    942 
    943   if (layout && height != pref->height()) {
    944     // We're doing a layout, and the height differs from the preferred height,
    945     // divy up the extra space.
    946     LayoutElement::DistributeDelta(height - pref->height(), &rows_);
    947 
    948     // Reset y locations.
    949     LayoutElement::CalculateLocationsFromSize(&rows_);
    950   }
    951 }
    952 
    953 void GridLayout::CalculateMasterColumnsIfNecessary() const {
    954   if (!calculated_master_columns_) {
    955     calculated_master_columns_ = true;
    956     for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
    957          i != column_sets_.end(); ++i) {
    958       (*i)->CalculateMasterColumns();
    959     }
    960   }
    961 }
    962 
    963 void GridLayout::AddViewState(ViewState* view_state) {
    964   DCHECK(view_state->view && (view_state->view->parent() == NULL ||
    965                               view_state->view->parent() == host_));
    966   if (!view_state->view->parent()) {
    967     adding_view_ = true;
    968     host_->AddChildView(view_state->view);
    969     adding_view_ = false;
    970   }
    971   remaining_row_span_ = std::max(remaining_row_span_, view_state->row_span);
    972   next_column_ += view_state->col_span;
    973   current_row_col_set_->AddViewState(view_state);
    974   // view_states are ordered by row_span (in ascending order).
    975   std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
    976                                                          view_states_.end(),
    977                                                          view_state,
    978                                                          CompareByRowSpan);
    979   view_states_.insert(i, view_state);
    980   SkipPaddingColumns();
    981 }
    982 
    983 void GridLayout::AddRow(Row* row) {
    984   current_row_++;
    985   remaining_row_span_--;
    986   // GridLayout requires that if you add a View with a row span you use the same
    987   // column set for each of the rows the view lands it. This DCHECK verifies
    988   // that.
    989   DCHECK(remaining_row_span_ <= 0 ||
    990          row->column_set() == NULL ||
    991          row->column_set() == GetLastValidColumnSet());
    992   next_column_ = 0;
    993   rows_.push_back(row);
    994   current_row_col_set_ = row->column_set();
    995   SkipPaddingColumns();
    996 }
    997 
    998 void GridLayout::UpdateRemainingHeightFromRows(ViewState* view_state) const {
    999   for (int i = 0, start_row = view_state->start_row;
   1000        i < view_state->row_span; ++i) {
   1001     view_state->remaining_height -= rows_[i + start_row]->Size();
   1002   }
   1003 }
   1004 
   1005 void GridLayout::DistributeRemainingHeight(ViewState* view_state) const {
   1006   int height = view_state->remaining_height;
   1007   if (height <= 0)
   1008     return;
   1009 
   1010   // Determine the number of resizable rows the view touches.
   1011   int resizable_rows = 0;
   1012   int start_row = view_state->start_row;
   1013   int max_row = view_state->start_row + view_state->row_span;
   1014   for (int i = start_row; i < max_row; ++i) {
   1015     if (rows_[i]->IsResizable()) {
   1016       resizable_rows++;
   1017     }
   1018   }
   1019 
   1020   if (resizable_rows > 0) {
   1021     // There are resizable rows, give the remaining height to them.
   1022     int to_distribute = height / resizable_rows;
   1023     for (int i = start_row; i < max_row; ++i) {
   1024       if (rows_[i]->IsResizable()) {
   1025         height -= to_distribute;
   1026         if (height < to_distribute) {
   1027           // Give all slop to the last column.
   1028           to_distribute += height;
   1029         }
   1030         rows_[i]->SetSize(rows_[i]->Size() + to_distribute);
   1031       }
   1032     }
   1033   } else {
   1034     // None of the rows are resizable, divy the remaining height up equally
   1035     // among all rows the view touches.
   1036     int each_row_height = height / view_state->row_span;
   1037     for (int i = start_row; i < max_row; ++i) {
   1038       height -= each_row_height;
   1039       if (height < each_row_height)
   1040         each_row_height += height;
   1041       rows_[i]->SetSize(rows_[i]->Size() + each_row_height);
   1042     }
   1043     view_state->remaining_height = 0;
   1044   }
   1045 }
   1046 
   1047 void GridLayout::SkipPaddingColumns() {
   1048   if (!current_row_col_set_)
   1049     return;
   1050   while (next_column_ < current_row_col_set_->num_columns() &&
   1051          current_row_col_set_->columns_[next_column_]->is_padding_) {
   1052     next_column_++;
   1053   }
   1054 }
   1055 
   1056 ColumnSet* GridLayout::GetLastValidColumnSet() {
   1057   for (int i = current_row_ - 1; i >= 0; --i) {
   1058     if (rows_[i]->column_set())
   1059       return rows_[i]->column_set();
   1060   }
   1061   return NULL;
   1062 }
   1063 
   1064 }  // namespace views
   1065