Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // For WinDDK ATL compatibility, these ATL headers must come first. | 5 // For WinDDK ATL compatibility, these ATL headers must come first. |
| 6 #include "build/build_config.h" | 6 #include "build/build_config.h" |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <atlbase.h> // NOLINT | 8 #include <atlbase.h> // NOLINT |
| 9 #include <atlwin.h> // NOLINT | 9 #include <atlwin.h> // NOLINT |
| 10 #endif | 10 #endif |
| 11 | 11 |
| 12 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h" | 12 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h" |
| 13 | 13 |
| 14 #include <algorithm> // NOLINT | 14 #include <algorithm> // NOLINT |
| 15 | 15 |
| 16 #include "base/i18n/bidi_line_iterator.h" | 16 #include "base/i18n/bidi_line_iterator.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" | |
| 18 #include "chrome/browser/search_engines/template_url.h" | |
| 19 #include "chrome/browser/search_engines/template_url_model.h" | |
| 17 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view_model.h" | 20 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view_model.h" |
| 18 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" | 21 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
| 19 #include "grit/generated_resources.h" | 22 #include "grit/generated_resources.h" |
| 20 #include "grit/theme_resources.h" | 23 #include "grit/theme_resources.h" |
| 21 #include "ui/base/l10n/l10n_util.h" | 24 #include "ui/base/l10n/l10n_util.h" |
| 22 #include "ui/base/resource/resource_bundle.h" | 25 #include "ui/base/resource/resource_bundle.h" |
| 23 #include "ui/base/text/text_elider.h" | 26 #include "ui/base/text/text_elider.h" |
| 24 #include "ui/gfx/canvas_skia.h" | 27 #include "ui/gfx/canvas_skia.h" |
| 25 #include "ui/gfx/color_utils.h" | 28 #include "ui/gfx/color_utils.h" |
| 29 #include "views/controls/image_view.h" | |
| 30 #include "views/controls/label.h" | |
| 26 | 31 |
| 27 #if defined(OS_LINUX) | 32 #if defined(OS_LINUX) |
| 28 #include "chrome/browser/ui/gtk/gtk_util.h" | 33 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 29 #include "ui/gfx/skia_utils_gtk.h" | 34 #include "ui/gfx/skia_utils_gtk.h" |
| 30 #endif | 35 #endif |
| 31 | 36 |
| 32 namespace { | 37 namespace { |
| 33 | 38 |
| 34 const char16 kEllipsis[] = { 0x2026 }; | 39 const char16 kEllipsis[] = { 0x2026 }; |
| 35 | 40 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 return right_ - x; | 104 return right_ - x; |
| 100 } | 105 } |
| 101 | 106 |
| 102 private: | 107 private: |
| 103 int center_; | 108 int center_; |
| 104 int right_; | 109 int right_; |
| 105 | 110 |
| 106 DISALLOW_COPY_AND_ASSIGN(MirroringContext); | 111 DISALLOW_COPY_AND_ASSIGN(MirroringContext); |
| 107 }; | 112 }; |
| 108 | 113 |
| 114 class AutocompleteResultView::IconLabelView : public views::View { | |
| 115 public: | |
| 116 explicit IconLabelView(gfx::Font font); | |
| 117 | |
| 118 virtual void Layout(); | |
| 119 virtual gfx::Size GetPreferredSize(); | |
| 120 virtual void OnPaint(gfx::Canvas* canvas); | |
| 121 | |
| 122 void SetLabelColor(SkColor color); | |
| 123 void SetLabelText(const string16& text); | |
| 124 void SetSelected(bool flag); | |
| 125 | |
| 126 private: | |
| 127 views::ImageView* image_; | |
| 128 views::Label* label_; | |
| 129 bool selected_; | |
| 130 | |
| 131 DISALLOW_COPY_AND_ASSIGN(IconLabelView); | |
| 132 }; | |
| 133 | |
| 134 AutocompleteResultView::IconLabelView::IconLabelView(gfx::Font font) | |
| 135 : selected_(false) { | |
| 136 image_ = new views::ImageView(); | |
| 137 AddChildView(image_); | |
| 138 image_->SetImage( | |
| 139 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_OMNIBOX_SEARCH)); | |
| 140 label_ = new views::Label(); | |
| 141 AddChildView(label_); | |
| 142 label_->SetFont(font); | |
| 143 label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 144 } | |
| 145 | |
| 146 void AutocompleteResultView::IconLabelView::Layout() { | |
| 147 const int icon_width = image_->GetPreferredSize().width(); | |
| 148 image_->SetBounds(LocationBarView::kItemPadding * 2, | |
| 149 (height() - icon_width) / 2, icon_width, icon_width); | |
| 150 const int label_padding = icon_width + LocationBarView::kItemPadding * 3; | |
| 151 const int label_height = label_->GetPreferredSize().height(); | |
| 152 label_->SetBounds(label_padding, (height() - label_height) / 2, width() - | |
| 153 label_padding, label_height); | |
| 154 } | |
| 155 | |
| 156 gfx::Size AutocompleteResultView::IconLabelView::GetPreferredSize() { | |
| 157 gfx::Size size(image_->GetPreferredSize()); | |
| 158 size.Enlarge(label_->GetPreferredSize().width() + | |
| 159 LocationBarView::kExtensionItemPadding + | |
| 160 LocationBarView::kItemPadding * 3, 0); | |
| 161 return size; | |
| 162 } | |
| 163 | |
| 164 void AutocompleteResultView::IconLabelView::OnPaint(gfx::Canvas* canvas) { | |
| 165 if (selected_) { | |
| 166 canvas->Save(); | |
| 167 canvas->ClipRectInt(LocationBarView::kItemPadding, 0, width() - | |
| 168 LocationBarView::kItemPadding, height()); | |
| 169 canvas->AsCanvasSkia()->drawColor(GetColor(SELECTED, BACKGROUND)); | |
| 170 canvas->Restore(); | |
| 171 } else { | |
| 172 canvas->AsCanvasSkia()->drawColor(GetColor(NORMAL, BACKGROUND)); | |
| 173 } | |
| 174 | |
| 175 SkPaint paint; | |
| 176 paint.setColor(GetColor(NORMAL, DIMMED_TEXT)); | |
| 177 paint.setStrokeWidth(SkIntToScalar(1)); | |
| 178 paint.setAntiAlias(true); | |
| 179 | |
| 180 canvas->AsCanvasSkia()->drawLine( | |
| 181 SkIntToScalar(LocationBarView::kVerticalEdgeThickness), | |
| 182 SkIntToScalar(LocationBarView::kNormalHorizontalEdgeThickness), | |
| 183 SkIntToScalar(LocationBarView::kVerticalEdgeThickness), | |
| 184 SkIntToScalar(height() - | |
| 185 LocationBarView::kNormalHorizontalEdgeThickness * 2), paint); | |
| 186 } | |
| 187 | |
| 188 void AutocompleteResultView::IconLabelView::SetLabelColor(SkColor color) { | |
| 189 label_->SetColor(color); | |
| 190 } | |
| 191 | |
| 192 void AutocompleteResultView::IconLabelView::SetLabelText(const string16& text) { | |
| 193 label_->SetText(UTF16ToWide(text)); | |
| 194 } | |
| 195 | |
| 196 void AutocompleteResultView::IconLabelView::SetSelected(bool flag) { | |
| 197 selected_ = flag; | |
| 198 | |
| 199 if (selected_) | |
| 200 image_->SetImage(ResourceBundle::GetSharedInstance(). | |
| 201 GetBitmapNamed(IDR_OMNIBOX_SEARCH_SELECTED)); | |
| 202 else | |
| 203 image_->SetImage(ResourceBundle::GetSharedInstance(). | |
| 204 GetBitmapNamed(IDR_OMNIBOX_SEARCH)); | |
| 205 | |
| 206 SchedulePaint(); | |
| 207 } | |
| 208 | |
| 109 AutocompleteResultView::AutocompleteResultView( | 209 AutocompleteResultView::AutocompleteResultView( |
| 110 AutocompleteResultViewModel* model, | 210 AutocompleteResultViewModel* model, |
| 111 int model_index, | 211 int model_index, |
| 112 const gfx::Font& font, | 212 const gfx::Font& font, |
| 113 const gfx::Font& bold_font) | 213 const gfx::Font& bold_font) |
| 114 : icon_vertical_padding_(kMinimumIconVerticalPadding), | 214 : icon_vertical_padding_(kMinimumIconVerticalPadding), |
| 115 text_vertical_padding_(kMinimumTextVerticalPadding), | 215 text_vertical_padding_(kMinimumTextVerticalPadding), |
| 116 model_(model), | 216 model_(model), |
| 117 model_index_(model_index), | 217 model_index_(model_index), |
| 118 normal_font_(font), | 218 normal_font_(font), |
| 119 bold_font_(bold_font), | 219 bold_font_(bold_font), |
| 120 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), | 220 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), |
| 121 mirroring_context_(new MirroringContext()), | 221 mirroring_context_(new MirroringContext()), |
| 122 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { | 222 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED), |
| 223 search_view_(new IconLabelView(font)), | |
| 224 search_expanded_(false), | |
| 225 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))) { | |
| 123 CHECK_GE(model_index, 0); | 226 CHECK_GE(model_index, 0); |
| 124 if (icon_size_ == 0) { | 227 if (icon_size_ == 0) { |
| 125 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 228 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| 126 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> | 229 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> |
| 127 width(); | 230 width(); |
| 128 } | 231 } |
| 232 | |
| 233 animation_->SetSlideDuration(500); | |
| 234 | |
| 235 AddChildView(search_view_.get()); | |
| 129 } | 236 } |
| 130 | 237 |
| 131 AutocompleteResultView::~AutocompleteResultView() { | 238 AutocompleteResultView::~AutocompleteResultView() { |
| 132 } | 239 } |
| 133 | 240 |
| 134 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { | 241 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { |
| 135 const ResultViewState state = GetState(); | 242 const ResultViewState state = GetState(); |
| 136 if (state != NORMAL) | 243 if (state != NORMAL && !search_expanded_) |
| 137 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); | 244 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); |
| 138 | 245 |
| 139 // Paint the icon. | 246 // Paint the icon. |
| 140 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), | 247 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), |
| 141 icon_bounds_.y()); | 248 icon_bounds_.y()); |
| 142 | 249 |
| 143 // Paint the text. | 250 // Paint the text. |
| 144 int x = GetMirroredXForRect(text_bounds_); | 251 int x = GetMirroredXForRect(text_bounds_); |
| 145 mirroring_context_->Initialize(x, text_bounds_.width()); | 252 mirroring_context_->Initialize(x, text_bounds_.width()); |
| 146 PaintMatch(canvas, match_, x); | 253 PaintMatch(canvas, match_, x); |
| 147 } | 254 } |
| 148 | 255 |
| 149 void AutocompleteResultView::Layout() { | 256 void AutocompleteResultView::Layout() { |
| 150 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding, | 257 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding, |
| 151 (height() - icon_size_) / 2, icon_size_, icon_size_); | 258 (height() - icon_size_) / 2, icon_size_, icon_size_); |
| 152 int text_x = icon_bounds_.right() + LocationBarView::kItemPadding; | 259 const int text_x = icon_bounds_.right() + LocationBarView::kItemPadding; |
| 153 int font_height = std::max(normal_font_.GetHeight(), bold_font_.GetHeight()); | 260 const int font_height = std::max(normal_font_.GetHeight(), |
| 154 text_bounds_.SetRect(text_x, std::max(0, (height() - font_height) / 2), | 261 bold_font_.GetHeight()); |
| 155 std::max(bounds().width() - text_x - LocationBarView::kEdgeItemPadding, | 262 const int text_y = std::max(0, (height() - font_height) / 2); |
| 156 0), font_height); | 263 |
| 264 if (keyword_.get() && keyword_->is_keyword_hint) { | |
| 265 gfx::Size search_size = search_view_->GetPreferredSize(); | |
| 266 const float expanded_x = static_cast<float>(text_x + | |
| 267 normal_font_.GetStringWidth(UTF8ToUTF16(ui::kEllipsis)) + | |
| 268 LocationBarView::kItemPadding); | |
| 269 const float collapsed_x = static_cast<float>(bounds().width() - | |
| 270 search_size.width()); | |
| 271 const int search_x = static_cast<int>(collapsed_x - ((collapsed_x - | |
| 272 expanded_x) * animation_->GetCurrentValue())); | |
| 273 | |
| 274 text_bounds_.SetRect(text_x, text_y, std::max(search_x - text_x, 0), | |
| 275 font_height); | |
| 276 search_view_->SetBounds(search_x, 0, std::max(bounds().width() - | |
| 277 search_x, 0), height()); | |
| 278 } else { | |
| 279 text_bounds_.SetRect(text_x, text_y, | |
| 280 std::max(bounds().width() - text_x, 0), font_height); | |
| 281 } | |
| 157 } | 282 } |
| 158 | 283 |
| 159 gfx::Size AutocompleteResultView::GetPreferredSize() { | 284 gfx::Size AutocompleteResultView::GetPreferredSize() { |
| 160 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_)); | 285 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_)); |
| 161 } | 286 } |
| 162 | 287 |
| 163 int AutocompleteResultView::GetPreferredHeight( | 288 int AutocompleteResultView::GetPreferredHeight( |
| 164 const gfx::Font& font, | 289 const gfx::Font& font, |
| 165 const gfx::Font& bold_font) { | 290 const gfx::Font& bold_font) { |
| 166 int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) + | 291 int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) + |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; | 387 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; |
| 263 } | 388 } |
| 264 | 389 |
| 265 const SkBitmap* AutocompleteResultView::GetIcon() const { | 390 const SkBitmap* AutocompleteResultView::GetIcon() const { |
| 266 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_); | 391 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_); |
| 267 if (bitmap) | 392 if (bitmap) |
| 268 return bitmap; | 393 return bitmap; |
| 269 | 394 |
| 270 int icon = match_.starred ? | 395 int icon = match_.starred ? |
| 271 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); | 396 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); |
| 272 if (model_->IsSelectedIndex(model_index_)) { | 397 if (model_->IsSelectedIndex(model_index_) && !search_expanded_) { |
| 273 switch (icon) { | 398 switch (icon) { |
| 274 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; | 399 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; |
| 275 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; | 400 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; |
| 276 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; | 401 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; |
| 277 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; | 402 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; |
| 278 default: NOTREACHED(); break; | 403 default: NOTREACHED(); break; |
| 279 } | 404 } |
| 280 } | 405 } |
| 281 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); | 406 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); |
| 282 } | 407 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 | 472 |
| 348 current_run->classifications.push_back(ClassificationData()); | 473 current_run->classifications.push_back(ClassificationData()); |
| 349 ClassificationData* current_data = | 474 ClassificationData* current_data = |
| 350 ¤t_run->classifications.back(); | 475 ¤t_run->classifications.back(); |
| 351 current_data->text = text.substr(text_start, text_end - text_start); | 476 current_data->text = text.substr(text_start, text_end - text_start); |
| 352 | 477 |
| 353 // Calculate style-related data. | 478 // Calculate style-related data. |
| 354 const int style = classifications[i].style; | 479 const int style = classifications[i].style; |
| 355 const bool use_bold_font = !!(style & ACMatchClassification::MATCH); | 480 const bool use_bold_font = !!(style & ACMatchClassification::MATCH); |
| 356 current_data->font = &(use_bold_font ? bold_font_ : normal_font_); | 481 current_data->font = &(use_bold_font ? bold_font_ : normal_font_); |
| 357 const ResultViewState state = GetState(); | 482 const ResultViewState state = search_expanded_ ? NORMAL : GetState(); |
| 358 if (style & ACMatchClassification::URL) | 483 if (style & ACMatchClassification::URL) |
| 359 current_data->color = GetColor(state, URL); | 484 current_data->color = GetColor(state, URL); |
| 360 else if (style & ACMatchClassification::DIM) | 485 else if (style & ACMatchClassification::DIM) |
| 361 current_data->color = GetColor(state, DIMMED_TEXT); | 486 current_data->color = GetColor(state, DIMMED_TEXT); |
| 362 else | 487 else |
| 363 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); | 488 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); |
| 364 current_data->pixel_width = | 489 current_data->pixel_width = |
| 365 current_data->font->GetStringWidth(current_data->text); | 490 current_data->font->GetStringWidth(current_data->text); |
| 366 current_run->pixel_width += current_data->pixel_width; | 491 current_run->pixel_width += current_data->pixel_width; |
| 367 } | 492 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 // * It's normal, and will be able to draw successfully with the | 628 // * It's normal, and will be able to draw successfully with the |
| 504 // ellipsis we'll append to it, or | 629 // ellipsis we'll append to it, or |
| 505 // * It is also bold, in which case we don't want to fall back | 630 // * It is also bold, in which case we don't want to fall back |
| 506 // to a normal ellipsis anyway (see comment above). | 631 // to a normal ellipsis anyway (see comment above). |
| 507 } | 632 } |
| 508 } | 633 } |
| 509 | 634 |
| 510 // We couldn't draw anything. | 635 // We couldn't draw anything. |
| 511 runs->clear(); | 636 runs->clear(); |
| 512 } | 637 } |
| 638 | |
| 639 void AutocompleteResultView::SetMatch(const AutocompleteMatch& match) { | |
| 640 const bool same_match = match.destination_url == match_.destination_url; | |
| 641 match_ = match; | |
| 642 keyword_ = match.keyword; | |
| 643 | |
| 644 const bool keyword_mode = keyword_.get() && keyword_->is_keyword_hint && | |
| 645 keyword_->is_keyword_mode; | |
| 646 | |
| 647 if (keyword_mode && !search_expanded_) | |
| 648 animation_->Show(); | |
| 649 else if (same_match && !keyword_mode && search_expanded_) | |
| 650 animation_->Hide(); | |
| 651 else if (!same_match || (same_match && !animation_->is_animating())) { | |
|
Peter Kasting
2011/04/11 23:17:33
Nit: All arms of a conditional need {} if one has
| |
| 652 animation_->Stop(); | |
| 653 animation_->Reset(); | |
| 654 } | |
| 655 | |
| 656 search_expanded_ = keyword_mode; | |
| 657 search_view_->SetSelected(search_expanded_); | |
| 658 search_view_->SetVisible(keyword_.get() && keyword_->is_keyword_hint); | |
| 659 | |
| 660 if (search_expanded_) { | |
| 661 int message_id = keyword_->template_url->IsExtensionKeyword() ? | |
| 662 IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH; | |
| 663 string16 text = l10n_util::GetStringFUTF16(message_id, | |
| 664 keyword_->text, l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); | |
| 665 text.append( | |
| 666 l10n_util::GetStringUTF16( | |
| 667 IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR)); | |
| 668 text.append( | |
| 669 l10n_util::GetStringFUTF16(IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION, | |
| 670 keyword_->text)); | |
| 671 search_view_->SetLabelText(text); | |
| 672 search_view_->SetLabelColor(GetColor(SELECTED, DIMMED_TEXT)); | |
| 673 } else { | |
| 674 search_view_->SetLabelText(UTF8ToUTF16(ui::kEllipsis)); | |
| 675 search_view_->SetLabelColor(GetColor(NORMAL, DIMMED_TEXT)); | |
| 676 } | |
| 677 Layout(); | |
| 678 } | |
| 679 | |
| 680 void AutocompleteResultView::AnimationProgressed( | |
| 681 const ui::Animation* animation) { | |
| 682 Layout(); | |
| 683 SchedulePaint(); | |
| 684 } | |
| 685 | |
| 686 void AutocompleteResultView::AnimationCanceled( | |
| 687 const ui::Animation* animation) { | |
| 688 Layout(); | |
| 689 SchedulePaint(); | |
| 690 } | |
| 691 | |
| OLD | NEW |