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