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

Side by Side Diff: ui/views/controls/button/label_button.cc

Issue 371633002: LabelButton: cache the last computed preferred size (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix whitespace Created 6 years, 5 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 unified diff | Download patch
« no previous file with comments | « ui/views/controls/button/label_button.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/controls/button/label_button.h" 5 #include "ui/views/controls/button/label_button.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "grit/ui_resources.h" 8 #include "grit/ui_resources.h"
9 #include "ui/base/resource/resource_bundle.h" 9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/animation/throb_animation.h" 10 #include "ui/gfx/animation/throb_animation.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 73
74 const gfx::ImageSkia& LabelButton::GetImage(ButtonState for_state) { 74 const gfx::ImageSkia& LabelButton::GetImage(ButtonState for_state) {
75 if (for_state != STATE_NORMAL && button_state_images_[for_state].isNull()) 75 if (for_state != STATE_NORMAL && button_state_images_[for_state].isNull())
76 return button_state_images_[STATE_NORMAL]; 76 return button_state_images_[STATE_NORMAL];
77 return button_state_images_[for_state]; 77 return button_state_images_[for_state];
78 } 78 }
79 79
80 void LabelButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) { 80 void LabelButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) {
81 button_state_images_[for_state] = image; 81 button_state_images_[for_state] = image;
82 UpdateImage(); 82 UpdateImage();
83 ResetCachedSize();
msw 2014/07/08 00:24:03 I think this call might be unnecessary if we have
noms (inactive) 2014/07/21 15:40:43 Done.
83 } 84 }
84 85
85 const base::string16& LabelButton::GetText() const { 86 const base::string16& LabelButton::GetText() const {
86 return label_->text(); 87 return label_->text();
87 } 88 }
88 89
89 void LabelButton::SetText(const base::string16& text) { 90 void LabelButton::SetText(const base::string16& text) {
90 SetAccessibleName(text); 91 SetAccessibleName(text);
91 label_->SetText(text); 92 label_->SetText(text);
93 ResetCachedSize();
92 } 94 }
93 95
94 void LabelButton::SetTextColor(ButtonState for_state, SkColor color) { 96 void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
95 button_state_colors_[for_state] = color; 97 button_state_colors_[for_state] = color;
96 if (for_state == STATE_DISABLED) 98 if (for_state == STATE_DISABLED)
97 label_->SetDisabledColor(color); 99 label_->SetDisabledColor(color);
98 else if (for_state == state()) 100 else if (for_state == state())
99 label_->SetEnabledColor(color); 101 label_->SetEnabledColor(color);
100 explicitly_set_colors_[for_state] = true; 102 explicitly_set_colors_[for_state] = true;
101 } 103 }
102 104
103 void LabelButton::SetTextShadows(const gfx::ShadowValues& shadows) { 105 void LabelButton::SetTextShadows(const gfx::ShadowValues& shadows) {
104 label_->set_shadows(shadows); 106 label_->set_shadows(shadows);
107 ResetCachedSize();
Evan Stade 2014/07/08 18:23:08 do shadows really affect the size of the button? t
noms (inactive) 2014/07/21 15:40:43 Done.
105 } 108 }
106 109
107 void LabelButton::SetTextSubpixelRenderingEnabled(bool enabled) { 110 void LabelButton::SetTextSubpixelRenderingEnabled(bool enabled) {
108 label_->set_subpixel_rendering_enabled(enabled); 111 label_->set_subpixel_rendering_enabled(enabled);
109 } 112 }
110 113
111 bool LabelButton::GetTextMultiLine() const { 114 bool LabelButton::GetTextMultiLine() const {
112 return label_->is_multi_line(); 115 return label_->is_multi_line();
113 } 116 }
114 117
115 void LabelButton::SetTextMultiLine(bool text_multi_line) { 118 void LabelButton::SetTextMultiLine(bool text_multi_line) {
116 label_->SetMultiLine(text_multi_line); 119 label_->SetMultiLine(text_multi_line);
120 ResetCachedSize();
117 } 121 }
118 122
119 const gfx::FontList& LabelButton::GetFontList() const { 123 const gfx::FontList& LabelButton::GetFontList() const {
120 return label_->font_list(); 124 return label_->font_list();
121 } 125 }
122 126
123 void LabelButton::SetFontList(const gfx::FontList& font_list) { 127 void LabelButton::SetFontList(const gfx::FontList& font_list) {
124 cached_normal_font_list_ = font_list; 128 cached_normal_font_list_ = font_list;
125 cached_bold_font_list_ = font_list.DeriveWithStyle( 129 cached_bold_font_list_ = font_list.DeriveWithStyle(
126 font_list.GetFontStyle() | gfx::Font::BOLD); 130 font_list.GetFontStyle() | gfx::Font::BOLD);
127 131
128 // STYLE_BUTTON uses bold text to indicate default buttons. 132 // STYLE_BUTTON uses bold text to indicate default buttons.
129 label_->SetFontList( 133 label_->SetFontList(
130 style_ == STYLE_BUTTON && is_default_ ? 134 style_ == STYLE_BUTTON && is_default_ ?
131 cached_bold_font_list_ : cached_normal_font_list_); 135 cached_bold_font_list_ : cached_normal_font_list_);
136 ResetCachedSize();
132 } 137 }
133 138
134 void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) { 139 void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
135 label_->SetElideBehavior(elide_behavior); 140 label_->SetElideBehavior(elide_behavior);
141 ResetCachedSize();
136 } 142 }
137 143
138 gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const { 144 gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const {
139 return label_->GetHorizontalAlignment(); 145 return label_->GetHorizontalAlignment();
140 } 146 }
141 147
142 void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) { 148 void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
143 label_->SetHorizontalAlignment(alignment); 149 label_->SetHorizontalAlignment(alignment);
msw 2014/07/08 00:24:03 I don't think the alignment should generally chang
noms (inactive) 2014/07/21 15:40:43 Done.
144 InvalidateLayout(); 150 InvalidateLayout();
145 } 151 }
146 152
147 void LabelButton::SetDirectionalityMode(gfx::DirectionalityMode mode) { 153 void LabelButton::SetDirectionalityMode(gfx::DirectionalityMode mode) {
148 label_->set_directionality_mode(mode); 154 label_->set_directionality_mode(mode);
msw 2014/07/08 00:24:04 The directionality could possibly change the prefe
noms (inactive) 2014/07/21 15:40:43 This went away after msw's CL.
149 } 155 }
150 156
151 void LabelButton::SetIsDefault(bool is_default) { 157 void LabelButton::SetIsDefault(bool is_default) {
152 if (is_default == is_default_) 158 if (is_default == is_default_)
153 return; 159 return;
154 is_default_ = is_default; 160 is_default_ = is_default;
155 ui::Accelerator accel(ui::VKEY_RETURN, ui::EF_NONE); 161 ui::Accelerator accel(ui::VKEY_RETURN, ui::EF_NONE);
156 is_default_ ? AddAccelerator(accel) : RemoveAccelerator(accel); 162 is_default_ ? AddAccelerator(accel) : RemoveAccelerator(accel);
157 163
158 // STYLE_BUTTON uses bold text to indicate default buttons. 164 // STYLE_BUTTON uses bold text to indicate default buttons.
159 if (style_ == STYLE_BUTTON) { 165 if (style_ == STYLE_BUTTON) {
160 label_->SetFontList( 166 label_->SetFontList(
161 is_default ? cached_bold_font_list_ : cached_normal_font_list_); 167 is_default ? cached_bold_font_list_ : cached_normal_font_list_);
162 } 168 }
163 } 169 }
164 170
165 void LabelButton::SetStyle(ButtonStyle style) { 171 void LabelButton::SetStyle(ButtonStyle style) {
msw 2014/07/08 00:24:03 Setting the style will definitely change the prefe
noms (inactive) 2014/07/21 15:40:43 Done.
166 style_ = style; 172 style_ = style;
167 // Inset the button focus rect from the actual border; roughly match Windows. 173 // Inset the button focus rect from the actual border; roughly match Windows.
168 if (style == STYLE_BUTTON) { 174 if (style == STYLE_BUTTON) {
169 SetFocusPainter(scoped_ptr<Painter>()); 175 SetFocusPainter(scoped_ptr<Painter>());
170 } else { 176 } else {
171 SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets( 177 SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
172 gfx::Insets(3, 3, 3, 3))); 178 gfx::Insets(3, 3, 3, 3)));
173 } 179 }
174 if (style == STYLE_BUTTON) { 180 if (style == STYLE_BUTTON) {
175 label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 181 label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
176 SetFocusable(true); 182 SetFocusable(true);
177 } 183 }
178 if (style == STYLE_BUTTON) 184 if (style == STYLE_BUTTON)
179 set_min_size(gfx::Size(70, 33)); 185 set_min_size(gfx::Size(70, 33));
180 186
181 OnNativeThemeChanged(GetNativeTheme()); 187 OnNativeThemeChanged(GetNativeTheme());
182 } 188 }
183 189
184 void LabelButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) { 190 void LabelButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
185 focus_painter_ = focus_painter.Pass(); 191 focus_painter_ = focus_painter.Pass();
186 } 192 }
187 193
188 gfx::Size LabelButton::GetPreferredSize() const { 194 gfx::Size LabelButton::GetPreferredSize() const {
189 // Use a temporary label copy for sizing to avoid calculation side-effects. 195 if (!button_size_valid_) {
msw 2014/07/08 00:24:03 nit: reverse condition and early return instead.
noms (inactive) 2014/07/21 15:40:43 Done.
190 Label label(GetText(), cached_normal_font_list_); 196 // Use a temporary label copy for sizing to avoid calculation side-effects.
191 label.set_shadows(label_->shadows()); 197 Label label(GetText(), cached_normal_font_list_);
192 label.SetMultiLine(GetTextMultiLine()); 198 label.set_shadows(label_->shadows());
199 label.SetMultiLine(GetTextMultiLine());
193 200
194 if (style() == STYLE_BUTTON) { 201 if (style() == STYLE_BUTTON) {
195 // Some text appears wider when rendered normally than when rendered bold. 202 // Some text appears wider when rendered normally than when rendered bold.
196 // Accommodate the widest, as buttons may show bold and shouldn't resize. 203 // Accommodate the widest, as buttons may show bold and shouldn't resize.
197 const int current_width = label.GetPreferredSize().width(); 204 const int current_width = label.GetPreferredSize().width();
198 label.SetFontList(cached_bold_font_list_); 205 label.SetFontList(cached_bold_font_list_);
199 if (label.GetPreferredSize().width() < current_width) 206 if (label.GetPreferredSize().width() < current_width)
200 label.SetFontList(cached_normal_font_list_); 207 label.SetFontList(cached_normal_font_list_);
208 }
209
210 // Resize multi-line labels given the current limited available width.
211 const gfx::Size image_size(image_->GetPreferredSize());
212 const int image_width = image_size.width();
213 if (GetTextMultiLine() && (width() > image_width + kSpacing))
214 label.SizeToFit(width() - image_width - (image_width > 0 ? kSpacing : 0));
215
216 // Calculate the required size.
217 gfx::Size size(label.GetPreferredSize());
218 if (image_width > 0 && size.width() > 0)
219 size.Enlarge(kSpacing, 0);
220 size.SetToMax(gfx::Size(0, image_size.height()));
221 const gfx::Insets insets(GetInsets());
222 size.Enlarge(image_size.width() + insets.width(), insets.height());
223
224 // Make the size at least as large as the minimum size needed by the border.
225 size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
226
227 // Increase the minimum size monotonically with the preferred size.
228 size.SetToMax(min_size_);
229 min_size_ = size;
230
231 // Return the largest known size clamped to the maximum size (if valid).
232 if (max_size_.width() > 0)
233 size.set_width(std::min(max_size_.width(), size.width()));
234 if (max_size_.height() > 0)
235 size.set_height(std::min(max_size_.height(), size.height()));
236
237 // Cache this computed size, as recomputing it is an expensive operation.
238 button_size_valid_ = true;
239 button_size_ = size;
201 } 240 }
202 241 return button_size_;
203 // Resize multi-line labels given the current limited available width.
204 const gfx::Size image_size(image_->GetPreferredSize());
205 const int image_width = image_size.width();
206 if (GetTextMultiLine() && (width() > image_width + kSpacing))
207 label.SizeToFit(width() - image_width - (image_width > 0 ? kSpacing : 0));
208
209 // Calculate the required size.
210 gfx::Size size(label.GetPreferredSize());
211 if (image_width > 0 && size.width() > 0)
212 size.Enlarge(kSpacing, 0);
213 size.SetToMax(gfx::Size(0, image_size.height()));
214 const gfx::Insets insets(GetInsets());
215 size.Enlarge(image_size.width() + insets.width(), insets.height());
216
217 // Make the size at least as large as the minimum size needed by the border.
218 size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
219
220 // Increase the minimum size monotonically with the preferred size.
221 size.SetToMax(min_size_);
222 min_size_ = size;
223
224 // Return the largest known size clamped to the maximum size (if valid).
225 if (max_size_.width() > 0)
226 size.set_width(std::min(max_size_.width(), size.width()));
227 if (max_size_.height() > 0)
228 size.set_height(std::min(max_size_.height(), size.height()));
229 return size;
230 } 242 }
231 243
232 void LabelButton::Layout() { 244 void LabelButton::Layout() {
233 gfx::HorizontalAlignment adjusted_alignment = GetHorizontalAlignment(); 245 gfx::HorizontalAlignment adjusted_alignment = GetHorizontalAlignment();
234 if (base::i18n::IsRTL() && adjusted_alignment != gfx::ALIGN_CENTER) 246 if (base::i18n::IsRTL() && adjusted_alignment != gfx::ALIGN_CENTER)
235 adjusted_alignment = (adjusted_alignment == gfx::ALIGN_LEFT) ? 247 adjusted_alignment = (adjusted_alignment == gfx::ALIGN_LEFT) ?
236 gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT; 248 gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
237 249
238 gfx::Rect child_area(GetChildAreaBounds()); 250 gfx::Rect child_area(GetChildAreaBounds());
239 child_area.Inset(GetInsets()); 251 child_area.Inset(GetInsets());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 } 288 }
277 289
278 const char* LabelButton::GetClassName() const { 290 const char* LabelButton::GetClassName() const {
279 return kViewClassName; 291 return kViewClassName;
280 } 292 }
281 293
282 scoped_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const { 294 scoped_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const {
283 return scoped_ptr<LabelButtonBorder>(new LabelButtonBorder(style_)); 295 return scoped_ptr<LabelButtonBorder>(new LabelButtonBorder(style_));
284 } 296 }
285 297
286 void LabelButton::SetBorder(scoped_ptr<Border> border) { 298 void LabelButton::SetBorder(scoped_ptr<Border> border) {
msw 2014/07/08 00:24:03 SetBorder may change the insets and thus the prefe
noms (inactive) 2014/07/21 15:40:43 Done.
287 border_is_themed_border_ = false; 299 border_is_themed_border_ = false;
288 View::SetBorder(border.Pass()); 300 View::SetBorder(border.Pass());
289 } 301 }
290 302
291 gfx::Rect LabelButton::GetChildAreaBounds() { 303 gfx::Rect LabelButton::GetChildAreaBounds() {
292 return GetLocalBounds(); 304 return GetLocalBounds();
293 } 305 }
294 306
295 void LabelButton::OnPaint(gfx::Canvas* canvas) { 307 void LabelButton::OnPaint(gfx::Canvas* canvas) {
296 View::OnPaint(canvas); 308 View::OnPaint(canvas);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 colors[STATE_HOVERED] = colors[STATE_PRESSED] = colors[STATE_NORMAL]; 373 colors[STATE_HOVERED] = colors[STATE_PRESSED] = colors[STATE_NORMAL];
362 374
363 for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state) { 375 for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state) {
364 if (!explicitly_set_colors_[state]) { 376 if (!explicitly_set_colors_[state]) {
365 SetTextColor(static_cast<ButtonState>(state), colors[state]); 377 SetTextColor(static_cast<ButtonState>(state), colors[state]);
366 explicitly_set_colors_[state] = false; 378 explicitly_set_colors_[state] = false;
367 } 379 }
368 } 380 }
369 } 381 }
370 382
371 void LabelButton::UpdateImage() { 383 void LabelButton::UpdateImage() {
msw 2014/07/08 00:24:03 Updating the image may change its preferred size,
noms (inactive) 2014/07/21 15:40:43 Acknowledged.
372 image_->SetImage(GetImage(state())); 384 image_->SetImage(GetImage(state()));
373 } 385 }
374 386
375 void LabelButton::UpdateThemedBorder() { 387 void LabelButton::UpdateThemedBorder() {
msw 2014/07/08 00:24:03 Looks like clearing on SetBorder would be sufficie
noms (inactive) 2014/07/21 15:40:43 Acknowledged.
376 // Don't override borders set by others. 388 // Don't override borders set by others.
377 if (!border_is_themed_border_) 389 if (!border_is_themed_border_)
378 return; 390 return;
379 391
380 scoped_ptr<LabelButtonBorder> label_button_border = CreateDefaultBorder(); 392 scoped_ptr<LabelButtonBorder> label_button_border = CreateDefaultBorder();
381 393
382 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 394 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
383 views::LinuxUI* linux_ui = views::LinuxUI::instance(); 395 views::LinuxUI* linux_ui = views::LinuxUI::instance();
384 if (linux_ui) { 396 if (linux_ui) {
385 SetBorder(linux_ui->CreateNativeBorder( 397 SetBorder(linux_ui->CreateNativeBorder(
386 this, label_button_border.Pass())); 398 this, label_button_border.Pass()));
387 } else 399 } else
388 #endif 400 #endif
389 { 401 {
390 SetBorder(label_button_border.PassAs<Border>()); 402 SetBorder(label_button_border.PassAs<Border>());
391 } 403 }
392 404
393 border_is_themed_border_ = true; 405 border_is_themed_border_ = true;
394 } 406 }
395 407
396 void LabelButton::StateChanged() { 408 void LabelButton::StateChanged() {
397 const gfx::Size previous_image_size(image_->GetPreferredSize()); 409 const gfx::Size previous_image_size(image_->GetPreferredSize());
398 UpdateImage(); 410 UpdateImage();
msw 2014/07/08 00:24:03 Updating the image may change the preferred size (
Evan Stade 2014/07/08 18:23:08 Having gone down this rabbit hole int the past, I'
399 const SkColor color = button_state_colors_[state()]; 411 const SkColor color = button_state_colors_[state()];
400 if (state() != STATE_DISABLED && label_->enabled_color() != color) 412 if (state() != STATE_DISABLED && label_->enabled_color() != color)
401 label_->SetEnabledColor(color); 413 label_->SetEnabledColor(color);
402 label_->SetEnabled(state() != STATE_DISABLED); 414 label_->SetEnabled(state() != STATE_DISABLED);
403 if (image_->GetPreferredSize() != previous_image_size) 415 if (image_->GetPreferredSize() != previous_image_size)
404 Layout(); 416 Layout();
405 } 417 }
406 418
407 void LabelButton::ChildPreferredSizeChanged(View* child) { 419 void LabelButton::ChildPreferredSizeChanged(View* child) {
msw 2014/07/08 00:24:04 This should definitely clear the cached preferred
noms (inactive) 2014/07/21 15:40:43 Done.
408 PreferredSizeChanged(); 420 PreferredSizeChanged();
409 } 421 }
410 422
411 void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { 423 void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
412 ResetColorsFromNativeTheme(); 424 ResetColorsFromNativeTheme();
413 UpdateThemedBorder(); 425 UpdateThemedBorder();
414 // Invalidate the layout to pickup the new insets from the border. 426 // Invalidate the layout to pickup the new insets from the border.
415 InvalidateLayout(); 427 InvalidateLayout();
416 } 428 }
417 429
(...skipping 27 matching lines...) Expand all
445 GetExtraParams(params); 457 GetExtraParams(params);
446 return ui::NativeTheme::kNormal; 458 return ui::NativeTheme::kNormal;
447 } 459 }
448 460
449 ui::NativeTheme::State LabelButton::GetForegroundThemeState( 461 ui::NativeTheme::State LabelButton::GetForegroundThemeState(
450 ui::NativeTheme::ExtraParams* params) const { 462 ui::NativeTheme::ExtraParams* params) const {
451 GetExtraParams(params); 463 GetExtraParams(params);
452 return ui::NativeTheme::kHovered; 464 return ui::NativeTheme::kHovered;
453 } 465 }
454 466
467 void LabelButton::ResetCachedSize() {
468 button_size_valid_ = false;
msw 2014/07/08 00:24:04 nit: avoid the flag and use empty as an invalid si
noms (inactive) 2014/07/21 15:40:43 Isn't it possible that a LabelButton would legitim
469 button_size_= gfx::Size();
470 }
471
455 } // namespace views 472 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/button/label_button.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698