Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Unified Diff: ui/views/window/dialog_client_view.cc

Issue 2706423002: Use GridLayout for DialogClientView's button row. (Closed)
Patch Set: Add a juicy test Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/views/window/dialog_client_view.cc
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
index deff7dc0a4423055a6afe1d258425abbdd327cff..2bacf40d2c51c507094b0cb09b710f49abfb9a73 100644
--- a/ui/views/window/dialog_client_view.cc
+++ b/ui/views/window/dialog_client_view.cc
@@ -15,6 +15,7 @@
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/layout/grid_layout.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
@@ -40,27 +41,36 @@ bool ShouldShow(View* view) {
return view && view->visible();
}
-// Do the layout for a button.
-void LayoutButton(LabelButton* button,
- gfx::Rect* row_bounds,
- int button_height) {
- if (!button)
- return;
-
- const gfx::Size size = button->GetPreferredSize();
- row_bounds->set_width(row_bounds->width() - size.width());
- DCHECK_LE(button_height, row_bounds->height());
- button->SetBounds(
- row_bounds->right(),
- row_bounds->y() + (row_bounds->height() - button_height) / 2,
- size.width(), button_height);
- const int spacing =
- ViewsDelegate::GetInstance()->GetDialogRelatedButtonHorizontalSpacing();
- row_bounds->set_width(row_bounds->width() - spacing);
+// Arrange two sizes vertically and return the bounding box.
Peter Kasting 2017/02/25 06:04:07 Nit: Descriptive ("Arranges"), not imperative. Ma
tapted 2017/02/27 10:04:19 Done.
+gfx::Size ArrangeVertically(const gfx::Size& above, const gfx::Size& below) {
Peter Kasting 2017/02/25 06:04:07 Nit: Trivial, but it technically doesn't matter th
tapted 2017/02/27 10:04:19 Done.
+ return gfx::Size(std::max(above.width(), below.width()),
+ above.height() + below.height());
}
} // namespace
+// Simple container to bubble child view changes up the view hierarchy.
+class DialogClientView::ButtonRowContainer : public View {
+ public:
+ ButtonRowContainer() {}
+
+ // Downcast so that ButtonRowContainer can call protected methods as a friend.
+ DialogClientView* parent() {
+ return static_cast<DialogClientView*>(View::parent());
Peter Kasting 2017/02/25 06:04:07 Nit: It would be safer to take the DialogClientVie
tapted 2017/02/27 10:04:19 Done.
+ }
+
+ // View:
+ void ChildPreferredSizeChanged(View* child) override {
+ parent()->ChildPreferredSizeChanged(child);
Peter Kasting 2017/02/25 06:04:07 Nit: Optional, but seems like the only reason we n
tapted 2017/02/27 10:04:19 This crossed my mind too.. but I decided not to at
Peter Kasting 2017/02/28 03:33:23 I'm fine leaving it to a followup. I think it's w
tapted 2017/02/28 06:52:42 Acknowledged.
+ }
+ void ChildVisibilityChanged(View* child) override {
+ parent()->ChildVisibilityChanged(child);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ButtonRowContainer);
+};
+
///////////////////////////////////////////////////////////////////////////////
// DialogClientView, public:
@@ -71,9 +81,14 @@ DialogClientView::DialogClientView(Widget* owner, View* contents_view)
// Doing this now ensures this accelerator will have lower priority than
// one set by the contents view.
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
+ button_row_container_ = new ButtonRowContainer();
+ AddChildView(button_row_container_);
}
DialogClientView::~DialogClientView() {
+ // The |extra_view_| can't participate in layout when it is not visible, so it
+ // might not be in the View hierarchy. Ensure it gets deleted.
+ delete extra_view_;
Peter Kasting 2017/02/25 06:04:07 I'm confused. Visibility and being part of the vi
tapted 2017/02/27 10:04:19 This is to satisfy some existing use-cases for Dia
Peter Kasting 2017/02/28 03:33:23 Where does this happen? Basically, I'm trying to
tapted 2017/02/28 06:52:42 Most overrides of DCV::CreateExtraView() hold on t
}
void DialogClientView::AcceptWindow() {
@@ -93,8 +108,8 @@ void DialogClientView::CancelWindow() {
}
void DialogClientView::UpdateDialogButtons() {
- SetupViews();
- SetupFocusChain();
+ SetupLayout();
+ InvalidateLayout();
}
///////////////////////////////////////////////////////////////////////////////
@@ -120,90 +135,30 @@ const DialogClientView* DialogClientView::AsDialogClientView() const {
// DialogClientView, View overrides:
gfx::Size DialogClientView::GetPreferredSize() const {
- // Initialize the size to fit the buttons and extra view row.
- gfx::Size size(
- (ok_button_ ? ok_button_->GetPreferredSize().width() : 0) +
- (cancel_button_ ? cancel_button_->GetPreferredSize().width() : 0) +
- (cancel_button_ && ok_button_
- ? ViewsDelegate::GetInstance()
- ->GetDialogRelatedButtonHorizontalSpacing()
- : 0) +
- (ShouldShow(extra_view_) ? extra_view_->GetPreferredSize().width()
- : 0) +
- GetExtraViewSpacing(),
- 0);
-
- int buttons_height = GetButtonsAndExtraViewRowHeight();
- if (buttons_height != 0) {
- size.Enlarge(0, buttons_height);
- // Inset the buttons and extra view.
- const gfx::Insets insets = GetButtonRowInsets();
- size.Enlarge(insets.width(), insets.height());
- }
-
- // Increase the size as needed to fit the contents view.
- // NOTE: The contents view is not inset on the top or side client view edges.
- gfx::Size contents_size = contents_view()->GetPreferredSize();
- size.Enlarge(0, contents_size.height());
- size.set_width(std::max(size.width(), contents_size.width()));
+ return ArrangeVertically(ClientView::GetPreferredSize(),
+ button_row_container_->GetPreferredSize());
+}
- size.SetToMax(minimum_size_);
+gfx::Size DialogClientView::GetMinimumSize() const {
+ return ArrangeVertically(ClientView::GetMinimumSize(),
+ button_row_container_->GetMinimumSize());
+}
- return size;
+gfx::Size DialogClientView::GetMaximumSize() const {
+ // The button layout doesn't currently have a maximum size.
Peter Kasting 2017/02/25 06:04:07 Maybe it should? Then we could probably just use
tapted 2017/02/27 10:04:19 Maximum size would need slightly different logic (
+ DCHECK(gfx::Size() == button_row_container_->GetMaximumSize());
Peter Kasting 2017/02/25 06:04:07 Nit: DCHECK(button_row_container_->GetMaximumSize(
tapted 2017/02/27 10:04:19 The maximum size can be constrained in a single di
+ gfx::Size max_size = ClientView::GetMaximumSize();
+ if (max_size != gfx::Size())
Peter Kasting 2017/02/25 06:04:07 Nit: !IsEmpty()?
tapted 2017/02/27 10:04:19 Changed this to if (max_size.height() != 0) an
Peter Kasting 2017/02/28 03:33:23 I don't think we should add a DLOG, because it's n
tapted 2017/02/28 06:52:42 Yeah the DLOG would only be an indicator for devel
+ max_size.Enlarge(0, button_row_container_->GetPreferredSize().height());
+ return max_size;
}
void DialogClientView::Layout() {
- gfx::Rect bounds = GetContentsBounds();
-
- // Layout the row containing the buttons and the extra view.
- if (has_dialog_buttons() || ShouldShow(extra_view_)) {
- gfx::Insets button_row_insets = GetButtonRowInsets();
- // Don't apply the top inset here because it's supposed to go above the
- // buttons, not at the top of the dialog.
- bounds.Inset(button_row_insets.left(), 0, button_row_insets.right(),
- button_row_insets.bottom());
- const int height = GetButtonsAndExtraViewRowHeight();
- gfx::Rect row_bounds(bounds.x(), bounds.bottom() - height,
- bounds.width(), height);
- // If the |extra_view_| is a also button, then the |button_height| is the
- // maximum height of the three buttons, otherwise it is the maximum height
- // of the ok and cancel buttons.
- const int button_height =
- CustomButton::AsCustomButton(extra_view_) ? height : GetButtonHeight();
- if (kIsOkButtonOnLeftSide) {
- LayoutButton(cancel_button_, &row_bounds, button_height);
- LayoutButton(ok_button_, &row_bounds, button_height);
- } else {
- LayoutButton(ok_button_, &row_bounds, button_height);
- LayoutButton(cancel_button_, &row_bounds, button_height);
- }
- if (extra_view_) {
- int custom_padding = 0;
- if (has_dialog_buttons() &&
- GetDialogDelegate()->GetExtraViewPadding(&custom_padding)) {
- // The padding between buttons applied in LayoutButton() will already
- // have accounted for some of the distance here.
- custom_padding -= ViewsDelegate::GetInstance()
- ->GetDialogRelatedButtonHorizontalSpacing();
- row_bounds.set_width(row_bounds.width() - custom_padding);
- }
- row_bounds.set_width(std::min(row_bounds.width(),
- extra_view_->GetPreferredSize().width()));
- extra_view_->SetBoundsRect(row_bounds);
- }
-
- if (height > 0) {
- // Inset to the top of the buttons, plus their top padding, in order to
- // exclude that area from the content view's bounds.
- bounds.Inset(0, 0, 0, height + button_row_insets.top());
- }
- }
-
- // Layout the contents view to the top and side edges of the contents bounds.
- // NOTE: The local insets do not apply to the contents view sides or top.
- const gfx::Rect contents_bounds = GetContentsBounds();
- contents_view()->SetBounds(contents_bounds.x(), contents_bounds.y(),
- contents_bounds.width(), bounds.bottom() - contents_bounds.y());
+ button_row_container_->SetSize(
+ gfx::Size(width(), button_row_container_->GetHeightForWidth(width())));
+ button_row_container_->SetY(height() - button_row_container_->height());
+ if (contents_view())
+ contents_view()->SetSize(gfx::Size(width(), button_row_container_->y()));
}
bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) {
@@ -217,23 +172,31 @@ void DialogClientView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
View* const child = details.child;
- // Dialogs must add children to contents_view(), not client_view().
- if (details.is_add && details.parent == this) {
- DCHECK(child == contents_view() || child == ok_button_ ||
tapted 2017/02/24 06:55:10 Ah, this DCHECK I added to get a jump on dialogs t
- child == cancel_button_ || child == extra_view_);
- }
-
ClientView::ViewHierarchyChanged(details);
- if (details.is_add && child == this) {
- UpdateDialogButtons();
- } else if (!details.is_add) {
- if (child == ok_button_)
- ok_button_ = nullptr;
- else if (child == cancel_button_)
- cancel_button_ = nullptr;
- else if (child == extra_view_)
- extra_view_ = nullptr;
+
+ if (details.is_add) {
+ if (child == this)
+ UpdateDialogButtons();
+ return;
}
+
+ if (details.parent != button_row_container_)
+ return;
+
+ // SetupViews() removes all children, managing data members itself.
+ if (in_setup_views_)
+ return;
+
+ // Otherwise, this should only happen during teardown. Ensure there are no
+ // references to deleted Views.
Peter Kasting 2017/02/25 06:04:07 Is this important? Are there races or something t
tapted 2017/02/27 10:04:19 It looks like this trend started a long time ago w
Peter Kasting 2017/02/28 03:33:23 Hmm, I didn't realize we had public accessors for
tapted 2017/02/28 06:52:42 Acknowledged.
+ button_row_container_->SetLayoutManager(nullptr);
+
+ if (child == ok_button_)
+ ok_button_ = nullptr;
+ else if (child == cancel_button_)
+ cancel_button_ = nullptr;
+ else if (child == extra_view_)
+ extra_view_ = nullptr;
}
void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
@@ -276,21 +239,37 @@ void DialogClientView::ChildPreferredSizeChanged(View* child) {
}
void DialogClientView::ChildVisibilityChanged(View* child) {
+ // Showing or hiding |extra_view_| can alter which columns have linked sizes.
+ if (child == extra_view_)
+ UpdateDialogButtons();
ChildPreferredSizeChanged(child);
}
-LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
- const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type);
+void DialogClientView::UpdateDialogButton(LabelButton** member,
+ ui::DialogButton type) {
+ DialogDelegate* const delegate = GetDialogDelegate();
+ if ((delegate->GetDialogButtons() & type) == 0) {
+ delete *member;
+ *member = nullptr;
+ return;
+ }
+
+ if (*member) {
+ delegate->UpdateButton(*member, type);
+ return;
+ }
+
+ const base::string16 title = delegate->GetDialogButtonLabel(type);
LabelButton* button = nullptr;
- const bool is_default =
- GetDialogDelegate()->GetDefaultDialogButton() == type &&
- (type != ui::DIALOG_BUTTON_CANCEL ||
- PlatformStyle::kDialogDefaultButtonCanBeCancel);
+ const bool is_default = delegate->GetDefaultDialogButton() == type &&
+ (type != ui::DIALOG_BUTTON_CANCEL ||
+ PlatformStyle::kDialogDefaultButtonCanBeCancel);
// The default button is always blue in Harmony.
- if (is_default && (ui::MaterialDesignController::IsSecondaryUiMaterial() ||
- GetDialogDelegate()->ShouldDefaultButtonBeBlue())) {
+ if (is_default &&
+ (ui::MaterialDesignController::IsSecondaryUiMaterial() ||
+ delegate->ShouldDefaultButtonBeBlue())) {
button = MdTextButton::CreateSecondaryUiBlueButton(this, title);
} else {
button = MdTextButton::CreateSecondaryUiButton(this, title);
@@ -303,66 +282,13 @@ LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
button->SetMinSize(gfx::Size(minimum_width, 0));
button->SetGroup(kButtonGroup);
- return button;
-}
-
-int DialogClientView::GetButtonHeight() const {
- return std::max(
- ok_button_ ? ok_button_->GetPreferredSize().height() : 0,
- cancel_button_ ? cancel_button_->GetPreferredSize().height() : 0);
-}
-
-int DialogClientView::GetExtraViewHeight() const {
- return ShouldShow(extra_view_) ? extra_view_->GetPreferredSize().height() : 0;
-}
-
-int DialogClientView::GetButtonsAndExtraViewRowHeight() const {
- return std::max(GetExtraViewHeight(), GetButtonHeight());
-}
-
-gfx::Insets DialogClientView::GetButtonRowInsets() const {
- if (GetButtonsAndExtraViewRowHeight() == 0)
- return gfx::Insets();
-
- // Some subclasses of DialogClientView, in order to do their own layout, set
- // button_row_insets_ to gfx::Insets(). To avoid breaking behavior of those
- // dialogs, supplying 0 for the top inset of the row falls back to
- // ViewsDelegate::GetRelatedControlVerticalSpacing.
- // TODO(bsep): The top inset should never be 0 when harmony is enabled.
- const int top = button_row_insets_.top() == 0
- ? ViewsDelegate::GetInstance()
- ->GetDialogRelatedControlVerticalSpacing()
- : button_row_insets_.top();
- return gfx::Insets(top, button_row_insets_.left(),
- button_row_insets_.bottom(), button_row_insets_.right());
-}
-void DialogClientView::SetupFocusChain() {
- // Create a vector of child views in the order of intended focus.
- std::vector<View*> child_views;
- child_views.push_back(contents_view());
- child_views.push_back(extra_view_);
- if (kIsOkButtonOnLeftSide) {
- child_views.push_back(ok_button_);
- child_views.push_back(cancel_button_);
- } else {
- child_views.push_back(cancel_button_);
- child_views.push_back(ok_button_);
- }
-
- // Remove all null views from the vector.
- child_views.erase(
- std::remove(child_views.begin(), child_views.end(), nullptr),
- child_views.end());
-
- // Setup focus by reordering views. It is not safe to use SetNextFocusableView
- // since child views may be added externally to this view.
- for (size_t i = 0; i < child_views.size(); i++)
- ReorderChildView(child_views[i], i);
+ *member = button;
+ delegate->UpdateButton(button, type);
}
int DialogClientView::GetExtraViewSpacing() const {
- if (!ShouldShow(extra_view_) || !has_dialog_buttons())
+ if (!ShouldShow(extra_view_) || !(ok_button_ || cancel_button_))
return 0;
int extra_view_padding = 0;
@@ -373,41 +299,129 @@ int DialogClientView::GetExtraViewSpacing() const {
->GetDialogRelatedButtonHorizontalSpacing();
}
-void DialogClientView::SetupViews() {
- const int buttons = GetDialogDelegate()->GetDialogButtons();
+std::vector<View*> DialogClientView::ButtonRowViews() {
+ View* first = ShouldShow(extra_view_) ? extra_view_ : nullptr;
+ View* second = cancel_button_;
+ View* third = ok_button_;
+ if (kIsOkButtonOnLeftSide)
+ std::swap(second, third);
+ std::vector<View*> views = {first, second, third};
- if (buttons & ui::DIALOG_BUTTON_OK) {
- if (!ok_button_) {
- ok_button_ = CreateDialogButton(ui::DIALOG_BUTTON_OK);
- AddChildView(ok_button_);
- }
+ // Remove all null views from the vector.
+ views.erase(std::remove(views.begin(), views.end(), nullptr), views.end());
+ return views;
+}
- GetDialogDelegate()->UpdateButton(ok_button_, ui::DIALOG_BUTTON_OK);
- } else if (ok_button_) {
- delete ok_button_;
- ok_button_ = nullptr;
+void DialogClientView::SetupLayout() {
+ GridLayout* layout = new GridLayout(button_row_container_);
+ layout->set_minimum_size(minimum_size_);
+
+ // Clobber any existing LayoutManager since it has weak references to child
+ // Views which may be removed by SetupViews().
+ button_row_container_->SetLayoutManager(layout);
+ SetupViews();
+ const std::vector<View*> views = ButtonRowViews();
+ if (views.empty())
+ return;
+
+ gfx::Insets insets = button_row_insets_;
+ // Support dialogs that clear |button_row_insets_| to do their own layout.
+ // They expect GetDialogRelatedControlVerticalSpacing() in this case.
+ // TODO(tapted): Remove this under Harmony.
+ if (insets.top() == 0) {
+ const int top =
+ ViewsDelegate::GetInstance()->GetDialogRelatedControlVerticalSpacing();
+ insets.Set(top, insets.left(), insets.bottom(), insets.right());
Peter Kasting 2017/02/25 06:04:07 Nit: We should probably just add per-side setters
tapted 2017/02/27 10:04:19 I hunted through codesearch, and did some "brutefo
Peter Kasting 2017/02/28 03:33:23 Hmm. I just wanted to set one side the other day,
}
- if (buttons & ui::DIALOG_BUTTON_CANCEL) {
- if (!cancel_button_) {
- cancel_button_ = CreateDialogButton(ui::DIALOG_BUTTON_CANCEL);
- AddChildView(cancel_button_);
- }
+ // The |resize_percent| constants. There's only one stretchy column (padding
+ // to the left of ok/cancel buttons).
+ constexpr float kFixed = 0.f;
+ constexpr float kStretchy = 1.f;
+
+ // Button row is [ extra <pad+stretchy> second <pad> third ]. Ensure the <pad>
+ // column is zero width if there isn't a button on either side.
+ // GetExtraViewSpacing() handles <pad+stretchy>.
+ const int button_spacing =
+ (ok_button_ && cancel_button_)
+ ? ViewsDelegate::GetInstance()
+ ->GetDialogRelatedButtonHorizontalSpacing()
+ : 0;
+
+ constexpr int kButtonRowId = 0;
+ ColumnSet* column_set = layout->AddColumnSet(kButtonRowId);
+
+ // Rather than giving |button_row_container_| a Border, incorporate the insets
+ // into the layout. This simplifies min/max size calculations.
+ column_set->AddPaddingColumn(kFixed, insets.left());
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(kStretchy, GetExtraViewSpacing());
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(kFixed, button_spacing);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(kFixed, insets.right());
+
+ // Track which columns to link sizes under MD.
+ constexpr int kExtraViewColumnIndex = 1;
+ constexpr int kSecondColumnIndex = 3;
+ constexpr int kThirdColumnIndex = 5;
+ int link[] = {-1, -1, -1};
+ size_t index = 0;
+
+ layout->StartRowWithPadding(kFixed, kButtonRowId, kFixed, insets.top());
+
+ // First column is only used if there is an extra view.
Peter Kasting 2017/02/25 06:04:07 I feel like with some cleverness this block and th
tapted 2017/02/27 10:04:19 I'd toyed with this a bit.. The ButtonRowViews() a
Peter Kasting 2017/02/28 03:33:23 OK.
tapted 2017/02/28 06:52:42 I got an idea for this. (extra_view_ gets in the w
+ if (ShouldShow(extra_view_)) {
+ layout->AddView(views[index]);
+ link[index] = kExtraViewColumnIndex;
+ ++index;
+ } else {
+ layout->SkipColumns(1);
+ }
- GetDialogDelegate()->UpdateButton(cancel_button_, ui::DIALOG_BUTTON_CANCEL);
- } else if (cancel_button_) {
- delete cancel_button_;
- cancel_button_ = nullptr;
+ // Second column is only used if there are 2 buttons.
+ if (ok_button_ && cancel_button_) {
+ layout->AddView(views[index]);
+ link[index] = kSecondColumnIndex;
+ ++index;
+ } else {
+ layout->SkipColumns(1);
+ }
+
+ // Last column is only used if a view remains (either OK or Cancel).
+ if (index < views.size()) {
+ layout->AddView(views[index]);
+ link[index] = kThirdColumnIndex;
}
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
Peter Kasting 2017/02/25 06:04:08 Should we just go ahead and link the column sizes
tapted 2017/02/27 10:04:19 Hm - that scares me a little. It's not just that s
Peter Kasting 2017/02/28 03:33:23 Well, we're only enlarging linked widths when they
tapted 2017/02/28 06:52:42 That does tend to be the case. I couldn't find any
Peter Kasting 2017/02/28 09:30:46 Man, we really shouldn't have a button saying "Cre
+ // Only link the extra view column if it is a button.
+ if (ShouldShow(extra_view_) && !CustomButton::AsCustomButton(extra_view_))
+ column_set->LinkColumnSizes(link[1], link[2], -1);
+ else
+ column_set->LinkColumnSizes(link[0], link[1], link[2], -1);
+ }
+ layout->AddPaddingRow(kFixed, insets.bottom());
+}
+
+void DialogClientView::SetupViews() {
+ {
+ base::AutoReset<bool> auto_reset(&in_setup_views_, true);
+ button_row_container_->RemoveAllChildViews(false /* delete children */);
+ }
+
+ UpdateDialogButton(&ok_button_, ui::DIALOG_BUTTON_OK);
+ UpdateDialogButton(&cancel_button_, ui::DIALOG_BUTTON_CANCEL);
+
if (extra_view_)
return;
extra_view_ = GetDialogDelegate()->CreateExtraView();
- if (extra_view_) {
+ if (extra_view_)
extra_view_->SetGroup(kButtonGroup);
- AddChildView(extra_view_);
- }
}
} // namespace views

Powered by Google App Engine
This is Rietveld 408576698