This source file includes following definitions.
- ResetSizes
- CalculateLocationsFromSize
- DistributeDelta
- TotalSize
- SetLocation
- Location
- AdjustSize
- ResetSize
- SetSize
- Size
- SetResizePercent
- ResizePercent
- IsResizable
- master_column_
- h_align
- v_align
- ResetSize
- GetLastMasterColumn
- UnifySameSizedColumnSizes
- AdjustSize
- max_descent_
- ResetSize
- column_set
- AdjustSizeForBaseline
- max_ascent
- max_descent
- CompareByColumnSpan
- CompareByRowSpan
- AddPaddingColumn
- AddColumn
- LinkColumnSizes
- AddColumn
- AddViewState
- CalculateMasterColumns
- AccumulateMasterColumns
- UnifySameSizedColumnSizes
- UpdateRemainingWidth
- DistributeRemainingWidth
- LayoutWidth
- GetColumnWidth
- ResetColumnXCoordinates
- CalculateSize
- Resize
- adding_view_
- CreatePanel
- SetInsets
- SetInsets
- AddColumnSet
- GetColumnSet
- StartRowWithPadding
- StartRow
- AddPaddingRow
- SkipColumns
- AddView
- AddView
- AddView
- AddView
- CalculateSize
- Installed
- Uninstalled
- ViewAdded
- ViewRemoved
- GetPreferredSize
- GetPreferredHeightForWidth
- SizeRowsAndColumns
- CalculateMasterColumnsIfNecessary
- AddViewState
- AddRow
- UpdateRemainingHeightFromRows
- DistributeRemainingHeight
- SkipPaddingColumns
- GetLastValidColumnSet
#include "ui/views/layout/grid_layout.h"
#include <algorithm>
#include "base/logging.h"
#include "base/stl_util.h"
#include "ui/gfx/insets.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/view.h"
#include "ui/views/window/dialog_delegate.h"
namespace views {
class LayoutElement {
public:
template <class T>
static void ResetSizes(std::vector<T*>* elements) {
for (typename std::vector<T*>::iterator i = elements->begin();
i != elements->end(); ++i) {
(*i)->ResetSize();
}
}
template <class T>
static void CalculateLocationsFromSize(std::vector<T*>* elements) {
int location = 0;
for (typename std::vector<T*>::iterator i = elements->begin();
i != elements->end(); ++i) {
(*i)->SetLocation(location);
location += (*i)->Size();
}
}
template <class T>
static void DistributeDelta(int delta, std::vector<T*>* elements) {
if (delta == 0)
return;
float total_percent = 0;
int resize_count = 0;
for (typename std::vector<T*>::iterator i = elements->begin();
i != elements->end(); ++i) {
total_percent += (*i)->ResizePercent();
if ((*i)->ResizePercent() > 0)
resize_count++;
}
if (total_percent == 0) {
return;
}
int remaining = delta;
int resized = resize_count;
for (typename std::vector<T*>::iterator i = elements->begin();
i != elements->end(); ++i) {
T* element = *i;
if (element->ResizePercent() > 0) {
int to_give;
if (--resized == 0) {
to_give = remaining;
} else {
to_give = static_cast<int>(delta *
(element->resize_percent_ / total_percent));
remaining -= to_give;
}
element->SetSize(element->Size() + to_give);
}
}
}
template <class T>
static int TotalSize(int start, int length, std::vector<T*>* elements) {
DCHECK(start >= 0 && length > 0 &&
start + length <= static_cast<int>(elements->size()));
int size = 0;
for (int i = start, max = start + length; i < max; ++i) {
size += (*elements)[i]->Size();
}
return size;
}
explicit LayoutElement(float resize_percent)
: resize_percent_(resize_percent) {
DCHECK(resize_percent >= 0);
}
virtual ~LayoutElement() {}
void SetLocation(int location) {
location_ = location;
}
int Location() {
return location_;
}
virtual void AdjustSize(int size) {
size_ = std::max(size_, size);
}
virtual void ResetSize() {
SetSize(0);
}
void SetSize(int size) {
size_ = size;
}
int Size() {
return size_;
}
void SetResizePercent(float percent) {
resize_percent_ = percent;
}
float ResizePercent() {
return resize_percent_;
}
bool IsResizable() {
return resize_percent_ > 0;
}
private:
float resize_percent_;
int location_;
int size_;
DISALLOW_COPY_AND_ASSIGN(LayoutElement);
};
class Column : public LayoutElement {
public:
Column(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
GridLayout::SizeType size_type,
int fixed_width,
int min_width,
size_t index,
bool is_padding)
: LayoutElement(resize_percent),
h_align_(h_align),
v_align_(v_align),
size_type_(size_type),
same_size_column_(-1),
fixed_width_(fixed_width),
min_width_(min_width),
index_(index),
is_padding_(is_padding),
master_column_(NULL) {}
virtual ~Column() {}
GridLayout::Alignment h_align() { return h_align_; }
GridLayout::Alignment v_align() { return v_align_; }
virtual void ResetSize() OVERRIDE;
private:
friend class ColumnSet;
friend class GridLayout;
Column* GetLastMasterColumn();
void UnifySameSizedColumnSizes();
virtual void AdjustSize(int size) OVERRIDE;
const GridLayout::Alignment h_align_;
const GridLayout::Alignment v_align_;
const GridLayout::SizeType size_type_;
int same_size_column_;
const int fixed_width_;
const int min_width_;
const size_t index_;
const bool is_padding_;
std::vector<Column*> same_size_columns_;
Column* master_column_;
DISALLOW_COPY_AND_ASSIGN(Column);
};
void Column::ResetSize() {
if (size_type_ == GridLayout::FIXED) {
SetSize(fixed_width_);
} else {
SetSize(min_width_);
}
}
Column* Column::GetLastMasterColumn() {
if (master_column_ == NULL) {
return NULL;
}
if (master_column_ == this) {
return this;
}
return master_column_->GetLastMasterColumn();
}
void Column::UnifySameSizedColumnSizes() {
DCHECK(master_column_ == this);
int size = 0;
for (std::vector<Column*>::iterator i = same_size_columns_.begin();
i != same_size_columns_.end(); ++i) {
size = std::max(size, (*i)->Size());
}
for (std::vector<Column*>::iterator i = same_size_columns_.begin();
i != same_size_columns_.end(); ++i) {
(*i)->SetSize(size);
}
}
void Column::AdjustSize(int size) {
if (size_type_ == GridLayout::USE_PREF)
LayoutElement::AdjustSize(size);
}
class Row : public LayoutElement {
public:
Row(bool fixed_height, int height, float resize_percent,
ColumnSet* column_set)
: LayoutElement(resize_percent),
fixed_height_(fixed_height),
height_(height),
column_set_(column_set),
max_ascent_(0),
max_descent_(0) {
}
virtual ~Row() {}
virtual void ResetSize() OVERRIDE {
max_ascent_ = max_descent_ = 0;
SetSize(height_);
}
ColumnSet* column_set() {
return column_set_;
}
void AdjustSizeForBaseline(int ascent, int descent) {
max_ascent_ = std::max(ascent, max_ascent_);
max_descent_ = std::max(descent, max_descent_);
AdjustSize(max_ascent_ + max_descent_);
}
int max_ascent() const {
return max_ascent_;
}
int max_descent() const {
return max_descent_;
}
private:
const bool fixed_height_;
const int height_;
ColumnSet* column_set_;
int max_ascent_;
int max_descent_;
DISALLOW_COPY_AND_ASSIGN(Row);
};
struct ViewState {
ViewState(ColumnSet* column_set, View* view, int start_col, int start_row,
int col_span, int row_span, GridLayout::Alignment h_align,
GridLayout::Alignment v_align, int pref_width, int pref_height)
: column_set(column_set),
view(view),
start_col(start_col),
start_row(start_row),
col_span(col_span),
row_span(row_span),
h_align(h_align),
v_align(v_align),
pref_width_fixed(pref_width > 0),
pref_height_fixed(pref_height > 0),
pref_width(pref_width),
pref_height(pref_height),
remaining_width(0),
remaining_height(0),
baseline(-1) {
DCHECK(view && start_col >= 0 && start_row >= 0 && col_span > 0 &&
row_span > 0 && start_col < column_set->num_columns() &&
(start_col + col_span) <= column_set->num_columns());
}
ColumnSet* const column_set;
View* const view;
const int start_col;
const int start_row;
const int col_span;
const int row_span;
const GridLayout::Alignment h_align;
const GridLayout::Alignment v_align;
const bool pref_width_fixed;
const bool pref_height_fixed;
int pref_width;
int pref_height;
int remaining_width;
int remaining_height;
int baseline;
};
static bool CompareByColumnSpan(const ViewState* v1, const ViewState* v2) {
return v1->col_span < v2->col_span;
}
static bool CompareByRowSpan(const ViewState* v1, const ViewState* v2) {
return v1->row_span < v2->row_span;
}
ColumnSet::ColumnSet(int id) : id_(id) {
}
ColumnSet::~ColumnSet() {
STLDeleteElements(&columns_);
}
void ColumnSet::AddPaddingColumn(float resize_percent, int width) {
AddColumn(GridLayout::FILL, GridLayout::FILL, resize_percent,
GridLayout::FIXED, width, width, true);
}
void ColumnSet::AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
GridLayout::SizeType size_type,
int fixed_width,
int min_width) {
AddColumn(h_align, v_align, resize_percent, size_type, fixed_width,
min_width, false);
}
void ColumnSet::LinkColumnSizes(int first, ...) {
va_list marker;
va_start(marker, first);
DCHECK(first >= 0 && first < num_columns());
for (int last = first, next = va_arg(marker, int); next != -1;
next = va_arg(marker, int)) {
DCHECK(next >= 0 && next < num_columns());
columns_[last]->same_size_column_ = next;
last = next;
}
va_end(marker);
}
void ColumnSet::AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
GridLayout::SizeType size_type,
int fixed_width,
int min_width,
bool is_padding) {
Column* column = new Column(h_align, v_align, resize_percent, size_type,
fixed_width, min_width, columns_.size(),
is_padding);
columns_.push_back(column);
}
void ColumnSet::AddViewState(ViewState* view_state) {
std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
view_states_.end(),
view_state,
CompareByColumnSpan);
view_states_.insert(i, view_state);
}
void ColumnSet::CalculateMasterColumns() {
for (std::vector<Column*>::iterator i = columns_.begin();
i != columns_.end(); ++i) {
Column* column = *i;
int same_size_column_index = column->same_size_column_;
if (same_size_column_index != -1) {
DCHECK(same_size_column_index >= 0 &&
same_size_column_index < static_cast<int>(columns_.size()));
Column* master_column = column->master_column_;
Column* same_size_column = columns_[same_size_column_index];
Column* same_size_column_master = same_size_column->master_column_;
if (master_column == NULL) {
if (same_size_column_master == NULL) {
column->master_column_ = column;
same_size_column->master_column_ = column;
column->same_size_columns_.push_back(same_size_column);
column->same_size_columns_.push_back(column);
} else {
same_size_column->GetLastMasterColumn()->
same_size_columns_.push_back(column);
column->master_column_ = same_size_column;
}
} else {
if (same_size_column_master == NULL) {
same_size_column->master_column_ = column;
column->GetLastMasterColumn()->same_size_columns_.
push_back(same_size_column);
} else if (column->GetLastMasterColumn() !=
same_size_column->GetLastMasterColumn()) {
std::vector<Column*>* same_size_columns =
&(column->GetLastMasterColumn()->same_size_columns_);
std::vector<Column*>* other_same_size_columns =
&(same_size_column->GetLastMasterColumn()->same_size_columns_);
same_size_columns->insert(same_size_columns->end(),
other_same_size_columns->begin(),
other_same_size_columns->end());
other_same_size_columns->clear();
same_size_column->GetLastMasterColumn()->master_column_ = column;
}
}
}
}
AccumulateMasterColumns();
}
void ColumnSet::AccumulateMasterColumns() {
DCHECK(master_columns_.empty());
for (std::vector<Column*>::iterator i = columns_.begin();
i != columns_.end(); ++i) {
Column* column = *i;
Column* master_column = column->GetLastMasterColumn();
if (master_column &&
std::find(master_columns_.begin(), master_columns_.end(),
master_column) == master_columns_.end()) {
master_columns_.push_back(master_column);
}
column->master_column_ = master_column;
}
}
void ColumnSet::UnifySameSizedColumnSizes() {
for (std::vector<Column*>::iterator i = master_columns_.begin();
i != master_columns_.end(); ++i) {
(*i)->UnifySameSizedColumnSizes();
}
}
void ColumnSet::UpdateRemainingWidth(ViewState* view_state) {
for (int i = view_state->start_col,
max_col = view_state->start_col + view_state->col_span;
i < max_col; ++i) {
view_state->remaining_width -= columns_[i]->Size();
}
}
void ColumnSet::DistributeRemainingWidth(ViewState* view_state) {
int width = view_state->remaining_width;
if (width <= 0) {
return;
}
int resizable_columns = 0;
int pref_size_columns = 0;
int start_col = view_state->start_col;
int max_col = view_state->start_col + view_state->col_span;
float total_resize = 0;
for (int i = start_col; i < max_col; ++i) {
if (columns_[i]->IsResizable()) {
total_resize += columns_[i]->ResizePercent();
resizable_columns++;
} else if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
pref_size_columns++;
}
}
if (resizable_columns > 0) {
int remaining_width = width;
for (int i = start_col, resize_i = 0; i < max_col; ++i) {
if (columns_[i]->IsResizable()) {
resize_i++;
int delta = (resize_i == resizable_columns) ? remaining_width :
static_cast<int>(width * columns_[i]->ResizePercent() /
total_resize);
remaining_width -= delta;
columns_[i]->SetSize(columns_[i]->Size() + delta);
}
}
} else if (pref_size_columns > 0) {
int to_distribute = width / pref_size_columns;
for (int i = start_col; i < max_col; ++i) {
if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
width -= to_distribute;
if (width < to_distribute)
to_distribute += width;
columns_[i]->SetSize(columns_[i]->Size() + to_distribute);
}
}
}
}
int ColumnSet::LayoutWidth() {
int width = 0;
for (std::vector<Column*>::iterator i = columns_.begin();
i != columns_.end(); ++i) {
width += (*i)->Size();
}
return width;
}
int ColumnSet::GetColumnWidth(int start_col, int col_span) {
return LayoutElement::TotalSize(start_col, col_span, &columns_);
}
void ColumnSet::ResetColumnXCoordinates() {
LayoutElement::CalculateLocationsFromSize(&columns_);
}
void ColumnSet::CalculateSize() {
gfx::Size pref;
for (std::vector<ViewState*>::iterator i = view_states_.begin();
i != view_states_.end(); ++i) {
ViewState* view_state = *i;
if (!view_state->pref_width_fixed || !view_state->pref_height_fixed) {
pref = view_state->view->GetPreferredSize();
if (!view_state->pref_width_fixed)
view_state->pref_width = pref.width();
if (!view_state->pref_height_fixed)
view_state->pref_height = pref.height();
}
view_state->remaining_width = pref.width();
view_state->remaining_height = pref.height();
}
LayoutElement::ResetSizes(&columns_);
std::vector<ViewState*>::iterator view_state_iterator =
view_states_.begin();
for (; view_state_iterator != view_states_.end() &&
(*view_state_iterator)->col_span == 1; ++view_state_iterator) {
ViewState* view_state = *view_state_iterator;
Column* column = columns_[view_state->start_col];
column->AdjustSize(view_state->pref_width);
view_state->remaining_width -= column->Size();
}
UnifySameSizedColumnSizes();
for (; view_state_iterator != view_states_.end(); ++view_state_iterator) {
ViewState* view_state = *view_state_iterator;
UpdateRemainingWidth(view_state);
DistributeRemainingWidth(view_state);
UnifySameSizedColumnSizes();
}
}
void ColumnSet::Resize(int delta) {
LayoutElement::DistributeDelta(delta, &columns_);
}
GridLayout::GridLayout(View* host)
: host_(host),
calculated_master_columns_(false),
remaining_row_span_(0),
current_row_(-1),
next_column_(0),
current_row_col_set_(NULL),
adding_view_(false) {
DCHECK(host);
}
GridLayout::~GridLayout() {
STLDeleteElements(&column_sets_);
STLDeleteElements(&view_states_);
STLDeleteElements(&rows_);
}
GridLayout* GridLayout::CreatePanel(View* host) {
GridLayout* layout = new GridLayout(host);
layout->SetInsets(kPanelVertMargin, kButtonHEdgeMarginNew,
kPanelVertMargin, kButtonHEdgeMarginNew);
return layout;
}
void GridLayout::SetInsets(int top, int left, int bottom, int right) {
insets_.Set(top, left, bottom, right);
}
void GridLayout::SetInsets(const gfx::Insets& insets) {
insets_ = insets;
}
ColumnSet* GridLayout::AddColumnSet(int id) {
DCHECK(GetColumnSet(id) == NULL);
ColumnSet* column_set = new ColumnSet(id);
column_sets_.push_back(column_set);
return column_set;
}
ColumnSet* GridLayout::GetColumnSet(int id) {
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
i != column_sets_.end(); ++i) {
if ((*i)->id_ == id) {
return *i;
}
}
return NULL;
}
void GridLayout::StartRowWithPadding(float vertical_resize, int column_set_id,
float padding_resize, int padding) {
AddPaddingRow(padding_resize, padding);
StartRow(vertical_resize, column_set_id);
}
void GridLayout::StartRow(float vertical_resize, int column_set_id) {
ColumnSet* column_set = GetColumnSet(column_set_id);
DCHECK(column_set);
AddRow(new Row(false, 0, vertical_resize, column_set));
}
void GridLayout::AddPaddingRow(float vertical_resize, int pixel_count) {
AddRow(new Row(true, pixel_count, vertical_resize, NULL));
}
void GridLayout::SkipColumns(int col_count) {
DCHECK(col_count > 0);
next_column_ += col_count;
DCHECK(current_row_col_set_ &&
next_column_ <= current_row_col_set_->num_columns());
SkipPaddingColumns();
}
void GridLayout::AddView(View* view) {
AddView(view, 1, 1);
}
void GridLayout::AddView(View* view, int col_span, int row_span) {
DCHECK(current_row_col_set_ &&
next_column_ < current_row_col_set_->num_columns());
Column* column = current_row_col_set_->columns_[next_column_];
AddView(view, col_span, row_span, column->h_align(), column->v_align());
}
void GridLayout::AddView(View* view, int col_span, int row_span,
Alignment h_align, Alignment v_align) {
AddView(view, col_span, row_span, h_align, v_align, 0, 0);
}
void GridLayout::AddView(View* view, int col_span, int row_span,
Alignment h_align, Alignment v_align,
int pref_width, int pref_height) {
DCHECK(current_row_col_set_ && col_span > 0 && row_span > 0 &&
(next_column_ + col_span) <= current_row_col_set_->num_columns());
DCHECK(v_align != BASELINE || row_span == 1);
ViewState* state =
new ViewState(current_row_col_set_, view, next_column_, current_row_,
col_span, row_span, h_align, v_align, pref_width,
pref_height);
AddViewState(state);
}
static void CalculateSize(int pref_size, GridLayout::Alignment alignment,
int* location, int* size) {
if (alignment != GridLayout::FILL) {
int available_size = *size;
*size = std::min(*size, pref_size);
switch (alignment) {
case GridLayout::LEADING:
break;
case GridLayout::BASELINE:
case GridLayout::CENTER:
*location += (available_size - *size) / 2;
break;
case GridLayout::TRAILING:
*location = *location + available_size - *size;
break;
default:
NOTREACHED();
}
}
}
void GridLayout::Installed(View* host) {
DCHECK(host_ == host);
}
void GridLayout::Uninstalled(View* host) {
DCHECK(host_ == host);
}
void GridLayout::ViewAdded(View* host, View* view) {
DCHECK(host_ == host && adding_view_);
}
void GridLayout::ViewRemoved(View* host, View* view) {
DCHECK(host_ == host);
}
void GridLayout::Layout(View* host) {
DCHECK(host_ == host);
gfx::Size pref;
SizeRowsAndColumns(true, host_->width(), host_->height(), &pref);
for (std::vector<ViewState*>::iterator i = view_states_.begin();
i != view_states_.end(); ++i) {
ViewState* view_state = *i;
ColumnSet* column_set = view_state->column_set;
View* view = (*i)->view;
DCHECK(view);
int x = column_set->columns_[view_state->start_col]->Location() +
insets_.left();
int width = column_set->GetColumnWidth(view_state->start_col,
view_state->col_span);
CalculateSize(view_state->pref_width, view_state->h_align,
&x, &width);
int y = rows_[view_state->start_row]->Location() + insets_.top();
int height = LayoutElement::TotalSize(view_state->start_row,
view_state->row_span, &rows_);
if (view_state->v_align == BASELINE && view_state->baseline != -1) {
y += rows_[view_state->start_row]->max_ascent() - view_state->baseline;
height = view_state->pref_height;
} else {
CalculateSize(view_state->pref_height, view_state->v_align, &y, &height);
}
view->SetBounds(x, y, width, height);
}
}
gfx::Size GridLayout::GetPreferredSize(View* host) {
DCHECK(host_ == host);
gfx::Size out;
SizeRowsAndColumns(false, 0, 0, &out);
out.SetSize(std::max(out.width(), minimum_size_.width()),
std::max(out.height(), minimum_size_.height()));
return out;
}
int GridLayout::GetPreferredHeightForWidth(View* host, int width) {
DCHECK(host_ == host);
gfx::Size pref;
SizeRowsAndColumns(false, width, 0, &pref);
return pref.height();
}
void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
gfx::Size* pref) {
CalculateMasterColumnsIfNecessary();
pref->SetSize(0, 0);
if (rows_.empty())
return;
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
i != column_sets_.end(); ++i) {
(*i)->CalculateSize();
pref->set_width(std::max(pref->width(), (*i)->LayoutWidth()));
}
pref->set_width(pref->width() + insets_.width());
width = width ? width : pref->width();
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
i != column_sets_.end(); ++i) {
(*i)->Resize(width - (*i)->LayoutWidth() - insets_.left() -
insets_.right());
(*i)->ResetColumnXCoordinates();
}
LayoutElement::ResetSizes(&rows_);
for (std::vector<ViewState*>::iterator i= view_states_.begin();
i != view_states_.end() ; ++i) {
ViewState* view_state = *i;
view_state->remaining_height = view_state->pref_height;
if (view_state->v_align == BASELINE)
view_state->baseline = view_state->view->GetBaseline();
if (view_state->h_align == FILL) {
int actual_width =
view_state->column_set->GetColumnWidth(view_state->start_col,
view_state->col_span);
if (actual_width != view_state->pref_width &&
!view_state->pref_height_fixed) {
view_state->pref_height =
view_state->view->GetHeightForWidth(actual_width);
view_state->remaining_height = view_state->pref_height;
}
}
}
std::vector<ViewState*>::iterator view_states_iterator = view_states_.begin();
for (; view_states_iterator != view_states_.end() &&
(*view_states_iterator)->row_span == 1; ++view_states_iterator) {
ViewState* view_state = *view_states_iterator;
Row* row = rows_[view_state->start_row];
row->AdjustSize(view_state->remaining_height);
if (view_state->baseline != -1 &&
view_state->baseline <= view_state->pref_height) {
row->AdjustSizeForBaseline(view_state->baseline,
view_state->pref_height - view_state->baseline);
}
view_state->remaining_height = 0;
}
for (; view_states_iterator != view_states_.end(); ++view_states_iterator) {
ViewState* view_state = *view_states_iterator;
UpdateRemainingHeightFromRows(view_state);
DistributeRemainingHeight(view_state);
}
LayoutElement::CalculateLocationsFromSize(&rows_);
pref->set_height(rows_[rows_.size() - 1]->Location() +
rows_[rows_.size() - 1]->Size() + insets_.height());
if (layout && height != pref->height()) {
LayoutElement::DistributeDelta(height - pref->height(), &rows_);
LayoutElement::CalculateLocationsFromSize(&rows_);
}
}
void GridLayout::CalculateMasterColumnsIfNecessary() {
if (!calculated_master_columns_) {
calculated_master_columns_ = true;
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
i != column_sets_.end(); ++i) {
(*i)->CalculateMasterColumns();
}
}
}
void GridLayout::AddViewState(ViewState* view_state) {
DCHECK(view_state->view && (view_state->view->parent() == NULL ||
view_state->view->parent() == host_));
if (!view_state->view->parent()) {
adding_view_ = true;
host_->AddChildView(view_state->view);
adding_view_ = false;
}
remaining_row_span_ = std::max(remaining_row_span_, view_state->row_span);
next_column_ += view_state->col_span;
current_row_col_set_->AddViewState(view_state);
std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
view_states_.end(),
view_state,
CompareByRowSpan);
view_states_.insert(i, view_state);
SkipPaddingColumns();
}
void GridLayout::AddRow(Row* row) {
current_row_++;
remaining_row_span_--;
DCHECK(remaining_row_span_ <= 0 ||
row->column_set() == NULL ||
row->column_set() == GetLastValidColumnSet());
next_column_ = 0;
rows_.push_back(row);
current_row_col_set_ = row->column_set();
SkipPaddingColumns();
}
void GridLayout::UpdateRemainingHeightFromRows(ViewState* view_state) {
for (int i = 0, start_row = view_state->start_row;
i < view_state->row_span; ++i) {
view_state->remaining_height -= rows_[i + start_row]->Size();
}
}
void GridLayout::DistributeRemainingHeight(ViewState* view_state) {
int height = view_state->remaining_height;
if (height <= 0)
return;
int resizable_rows = 0;
int start_row = view_state->start_row;
int max_row = view_state->start_row + view_state->row_span;
for (int i = start_row; i < max_row; ++i) {
if (rows_[i]->IsResizable()) {
resizable_rows++;
}
}
if (resizable_rows > 0) {
int to_distribute = height / resizable_rows;
for (int i = start_row; i < max_row; ++i) {
if (rows_[i]->IsResizable()) {
height -= to_distribute;
if (height < to_distribute) {
to_distribute += height;
}
rows_[i]->SetSize(rows_[i]->Size() + to_distribute);
}
}
} else {
int each_row_height = height / view_state->row_span;
for (int i = start_row; i < max_row; ++i) {
height -= each_row_height;
if (height < each_row_height)
each_row_height += height;
rows_[i]->SetSize(rows_[i]->Size() + each_row_height);
}
view_state->remaining_height = 0;
}
}
void GridLayout::SkipPaddingColumns() {
if (!current_row_col_set_)
return;
while (next_column_ < current_row_col_set_->num_columns() &&
current_row_col_set_->columns_[next_column_]->is_padding_) {
next_column_++;
}
}
ColumnSet* GridLayout::GetLastValidColumnSet() {
for (int i = current_row_ - 1; i >= 0; --i) {
if (rows_[i]->column_set())
return rows_[i]->column_set();
}
return NULL;
}
}