OLD | NEW |
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 <algorithm> | 5 #include <algorithm> |
6 #include <vector> | 6 #include <vector> |
7 | 7 |
| 8 #include "base/time.h" |
8 #include "base/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
9 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
10 #include "chrome/browser/ui/browser_navigator.h" | 11 #include "chrome/browser/ui/browser_navigator.h" |
11 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" | 12 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" |
12 #include "chrome/browser/ui/intents/web_intent_picker.h" | 13 #include "chrome/browser/ui/intents/web_intent_picker.h" |
13 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" | 14 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" |
14 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | 15 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
15 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h" | 16 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h" |
16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 17 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
17 #include "chrome/browser/ui/views/constrained_window_views.h" | 18 #include "chrome/browser/ui/views/constrained_window_views.h" |
18 #include "chrome/browser/ui/views/frame/browser_view.h" | 19 #include "chrome/browser/ui/views/frame/browser_view.h" |
19 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" | 20 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" |
20 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h" | 21 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h" |
21 #include "chrome/browser/ui/views/toolbar_view.h" | 22 #include "chrome/browser/ui/views/toolbar_view.h" |
22 #include "chrome/browser/ui/views/window.h" | 23 #include "chrome/browser/ui/views/window.h" |
23 #include "chrome/common/extensions/extension_constants.h" | 24 #include "chrome/common/extensions/extension_constants.h" |
24 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
25 #include "content/public/browser/web_contents_view.h" | 26 #include "content/public/browser/web_contents_view.h" |
26 #include "grit/chromium_strings.h" | 27 #include "grit/chromium_strings.h" |
27 #include "grit/generated_resources.h" | 28 #include "grit/generated_resources.h" |
28 #include "grit/google_chrome_strings.h" | 29 #include "grit/google_chrome_strings.h" |
29 #include "grit/theme_resources.h" | 30 #include "grit/theme_resources.h" |
| 31 #include "grit/ui_resources.h" |
30 #include "grit/ui_resources_standard.h" | 32 #include "grit/ui_resources_standard.h" |
31 #include "third_party/skia/include/core/SkColor.h" | 33 #include "third_party/skia/include/core/SkColor.h" |
32 #include "ui/base/l10n/l10n_util.h" | 34 #include "ui/base/l10n/l10n_util.h" |
33 #include "ui/base/resource/resource_bundle.h" | 35 #include "ui/base/resource/resource_bundle.h" |
34 #include "ui/base/text/text_elider.h" | 36 #include "ui/base/text/text_elider.h" |
35 #include "ui/gfx/canvas.h" | 37 #include "ui/gfx/canvas.h" |
36 #include "ui/gfx/image/image.h" | 38 #include "ui/gfx/image/image.h" |
37 #include "ui/views/border.h" | 39 #include "ui/views/border.h" |
38 #include "ui/views/controls/button/image_button.h" | 40 #include "ui/views/controls/button/image_button.h" |
39 #include "ui/views/controls/button/text_button.h" | 41 #include "ui/views/controls/button/text_button.h" |
(...skipping 29 matching lines...) Expand all Loading... |
69 | 71 |
70 // The maximum width in pixels of a suggested extension's title link. | 72 // The maximum width in pixels of a suggested extension's title link. |
71 const int kTitleLinkMaxWidth = 130; | 73 const int kTitleLinkMaxWidth = 130; |
72 | 74 |
73 // The color used to dim disabled elements. | 75 // The color used to dim disabled elements. |
74 const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255); | 76 const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255); |
75 | 77 |
76 // The color used to display a disabled link. | 78 // The color used to display a disabled link. |
77 const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128); | 79 const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128); |
78 | 80 |
| 81 // The time between successive throbber frames in milliseconds. |
| 82 const int kThrobberFrameTimeMs = 60; |
| 83 |
79 // Enables or disables all child views of |view|. | 84 // Enables or disables all child views of |view|. |
80 void EnableChildViews(views::View* view, bool enabled) { | 85 void EnableChildViews(views::View* view, bool enabled) { |
81 for (int i = 0; i < view->child_count(); ++i) { | 86 for (int i = 0; i < view->child_count(); ++i) { |
82 views::View* child = view->child_at(i); | 87 views::View* child = view->child_at(i); |
83 child->SetEnabled(enabled); | 88 child->SetEnabled(enabled); |
84 } | 89 } |
85 } | 90 } |
86 | 91 |
87 // StarsView ------------------------------------------------------------------- | 92 // StarsView ------------------------------------------------------------------- |
88 | 93 |
(...skipping 29 matching lines...) Expand all Loading... |
118 // TODO(binji): Add tooltip with text rating | 123 // TODO(binji): Add tooltip with text rating |
119 // "Average Rating: X.XX stars (YYYYY)" | 124 // "Average Rating: X.XX stars (YYYYY)" |
120 // Y = "1: Hated it, 2: Disliked it, 3: It was okay, 4: Liked it, | 125 // Y = "1: Hated it, 2: Disliked it, 3: It was okay, 4: Liked it, |
121 // 5: Loved it" | 126 // 5: Loved it" |
122 // Choose Y based on rounded X. | 127 // Choose Y based on rounded X. |
123 } | 128 } |
124 | 129 |
125 StarsView::~StarsView() { | 130 StarsView::~StarsView() { |
126 } | 131 } |
127 | 132 |
| 133 // ThrobberNativeTextButton ---------------------------------------------------- |
| 134 |
| 135 // A native text button that can display a throbber in place of its icon. Much |
| 136 // of the logic of this class is copied from ui/views/controls/throbber.h. |
| 137 class ThrobberNativeTextButton : public views::NativeTextButton { |
| 138 public: |
| 139 ThrobberNativeTextButton(views::ButtonListener* listener, |
| 140 const string16& text); |
| 141 ~ThrobberNativeTextButton(); |
| 142 |
| 143 // Start or stop the throbber. |
| 144 void StartThrobber(); |
| 145 void StopThrobber(); |
| 146 |
| 147 // Set the throbber bitmap to use. IDR_THROBBER is used by default. |
| 148 void SetFrames(const SkBitmap* frames); |
| 149 |
| 150 protected: |
| 151 virtual const SkBitmap& GetImageToPaint() const OVERRIDE; |
| 152 |
| 153 private: |
| 154 // The timer callback to schedule painting this view. |
| 155 void Run(); |
| 156 |
| 157 // Bitmap that contains the throbber frames. |
| 158 const SkBitmap* frames_; |
| 159 |
| 160 // The currently displayed frame, given to GetImageToPaint. |
| 161 mutable SkBitmap this_frame_; |
| 162 |
| 163 // How long one frame is displayed. |
| 164 base::TimeDelta frame_time_; |
| 165 |
| 166 // Used to schedule Run calls. |
| 167 base::RepeatingTimer<ThrobberNativeTextButton> timer_; |
| 168 |
| 169 // How many frames we have. |
| 170 int frame_count_; |
| 171 |
| 172 // Time when StartThrobber was called. |
| 173 base::Time start_time_; |
| 174 |
| 175 // Whether the throbber is shown an animating. |
| 176 bool running_; |
| 177 }; |
| 178 |
| 179 ThrobberNativeTextButton::ThrobberNativeTextButton( |
| 180 views::ButtonListener* listener, const string16& text) |
| 181 : NativeTextButton(listener, text), |
| 182 frame_time_(base::TimeDelta::FromMilliseconds(kThrobberFrameTimeMs)), |
| 183 frame_count_(0), |
| 184 running_(false) { |
| 185 SetFrames(ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| 186 IDR_THROBBER).ToSkBitmap()); |
| 187 } |
| 188 |
| 189 ThrobberNativeTextButton::~ThrobberNativeTextButton() { |
| 190 StopThrobber(); |
| 191 } |
| 192 |
| 193 void ThrobberNativeTextButton::StartThrobber() { |
| 194 if (running_) |
| 195 return; |
| 196 |
| 197 start_time_ = base::Time::Now(); |
| 198 timer_.Start(FROM_HERE, frame_time_ - base::TimeDelta::FromMilliseconds(10), |
| 199 this, &ThrobberNativeTextButton::Run); |
| 200 running_ = true; |
| 201 |
| 202 SchedulePaint(); |
| 203 } |
| 204 |
| 205 void ThrobberNativeTextButton::StopThrobber() { |
| 206 if (!running_) |
| 207 return; |
| 208 |
| 209 timer_.Stop(); |
| 210 running_ = false; |
| 211 } |
| 212 |
| 213 void ThrobberNativeTextButton::SetFrames(const SkBitmap* frames) { |
| 214 frames_ = frames; |
| 215 DCHECK(frames_->width() > 0 && frames_->height() > 0); |
| 216 DCHECK(frames_->width() % frames_->height() == 0); |
| 217 frame_count_ = frames_->width() / frames_->height(); |
| 218 PreferredSizeChanged(); |
| 219 } |
| 220 |
| 221 const SkBitmap& ThrobberNativeTextButton::GetImageToPaint() const { |
| 222 if (!running_) |
| 223 return NativeTextButton::GetImageToPaint(); |
| 224 |
| 225 const base::TimeDelta elapsed_time = base::Time::Now() - start_time_; |
| 226 const int current_frame = |
| 227 static_cast<int>(elapsed_time / frame_time_) % frame_count_; |
| 228 const int image_size = frames_->height(); |
| 229 const int image_offset = current_frame * image_size; |
| 230 |
| 231 SkIRect subset_rect = SkIRect::MakeXYWH(image_offset, 0, |
| 232 image_size, image_size); |
| 233 frames_->extractSubset(&this_frame_, subset_rect); |
| 234 return this_frame_; |
| 235 } |
| 236 |
| 237 void ThrobberNativeTextButton::Run() { |
| 238 DCHECK(running_); |
| 239 |
| 240 SchedulePaint(); |
| 241 } |
| 242 |
128 // ServiceButtonsView ---------------------------------------------------------- | 243 // ServiceButtonsView ---------------------------------------------------------- |
129 | 244 |
130 // A view that contains all service buttons (i.e. the installed services). | 245 // A view that contains all service buttons (i.e. the installed services). |
131 class ServiceButtonsView : public views::View, | 246 class ServiceButtonsView : public views::View, |
132 public views::ButtonListener { | 247 public views::ButtonListener { |
133 public: | 248 public: |
134 class Delegate { | 249 class Delegate { |
135 public: | 250 public: |
136 // Called when a service button is clicked. |index| is the index of the | 251 // Called when a service button is clicked. |index| is the index of the |
137 // service button in the model. | 252 // service button in the model. |
138 virtual void OnServiceButtonClicked( | 253 virtual void OnServiceButtonClicked( |
139 const WebIntentPickerModel::InstalledService& service) = 0; | 254 const WebIntentPickerModel::InstalledService& service) = 0; |
140 | 255 |
141 protected: | 256 protected: |
142 virtual ~Delegate() {} | 257 virtual ~Delegate() {} |
143 }; | 258 }; |
144 | 259 |
145 ServiceButtonsView(const WebIntentPickerModel* model, Delegate* delegate); | 260 ServiceButtonsView(const WebIntentPickerModel* model, Delegate* delegate); |
146 virtual ~ServiceButtonsView(); | 261 virtual ~ServiceButtonsView(); |
147 | 262 |
148 // Updates the service button view with new model data. | 263 // Updates the service button view with new model data. |
149 void Update(); | 264 void Update(); |
150 | 265 |
| 266 // Start a throbber on the service button that will launch the service at |
| 267 // |url|. |
| 268 void StartThrobber(const GURL& url); |
| 269 |
151 // views::ButtonListener implementation. | 270 // views::ButtonListener implementation. |
152 virtual void ButtonPressed(views::Button* sender, | 271 virtual void ButtonPressed(views::Button* sender, |
153 const views::Event& event) OVERRIDE; | 272 const views::Event& event) OVERRIDE; |
154 | 273 |
155 virtual gfx::Size GetPreferredSize() OVERRIDE; | 274 virtual gfx::Size GetPreferredSize() OVERRIDE; |
156 | 275 |
157 protected: | 276 protected: |
158 virtual void OnEnabledChanged() OVERRIDE; | 277 virtual void OnEnabledChanged() OVERRIDE; |
159 | 278 |
160 private: | 279 private: |
(...skipping 26 matching lines...) Expand all Loading... |
187 cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF, | 306 cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF, |
188 0, 0); | 307 0, 0); |
189 cs->AddPaddingColumn(1, 0); | 308 cs->AddPaddingColumn(1, 0); |
190 | 309 |
191 for (size_t i = 0; i < model_->GetInstalledServiceCount(); ++i) { | 310 for (size_t i = 0; i < model_->GetInstalledServiceCount(); ++i) { |
192 const WebIntentPickerModel::InstalledService& service = | 311 const WebIntentPickerModel::InstalledService& service = |
193 model_->GetInstalledServiceAt(i); | 312 model_->GetInstalledServiceAt(i); |
194 | 313 |
195 grid_layout->StartRow(0, 0); | 314 grid_layout->StartRow(0, 0); |
196 | 315 |
197 views::NativeTextButton* button = | 316 ThrobberNativeTextButton* button = |
198 new views::NativeTextButton(this, service.title); | 317 new ThrobberNativeTextButton(this, service.title); |
199 button->set_alignment(views::TextButton::ALIGN_LEFT); | 318 button->set_alignment(views::TextButton::ALIGN_LEFT); |
200 button->SetTooltipText(UTF8ToUTF16(service.url.spec().c_str())); | 319 button->SetTooltipText(UTF8ToUTF16(service.url.spec().c_str())); |
201 button->SetIcon(*service.favicon.ToSkBitmap()); | 320 button->SetIcon(*service.favicon.ToSkBitmap()); |
202 button->set_tag(static_cast<int>(i)); | 321 button->set_tag(static_cast<int>(i)); |
203 grid_layout->AddView(button); | 322 grid_layout->AddView(button); |
204 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | 323 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
205 } | 324 } |
206 | 325 |
207 // Additional space to separate the buttons from the suggestions. | 326 // Additional space to separate the buttons from the suggestions. |
208 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); | 327 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
209 } | 328 } |
210 | 329 |
| 330 void ServiceButtonsView::StartThrobber(const GURL& url) { |
| 331 for (size_t i = 0; i < model_->GetInstalledServiceCount(); ++i) { |
| 332 const WebIntentPickerModel::InstalledService& service = |
| 333 model_->GetInstalledServiceAt(i); |
| 334 if (service.url != url) |
| 335 continue; |
| 336 |
| 337 ThrobberNativeTextButton* button = |
| 338 static_cast<ThrobberNativeTextButton*>(child_at(i)); |
| 339 button->StartThrobber(); |
| 340 return; |
| 341 } |
| 342 } |
| 343 |
211 void ServiceButtonsView::ButtonPressed(views::Button* sender, | 344 void ServiceButtonsView::ButtonPressed(views::Button* sender, |
212 const views::Event& event) { | 345 const views::Event& event) { |
213 size_t index = static_cast<size_t>(sender->tag()); | 346 size_t index = static_cast<size_t>(sender->tag()); |
214 delegate_->OnServiceButtonClicked(model_->GetInstalledServiceAt(index)); | 347 delegate_->OnServiceButtonClicked(model_->GetInstalledServiceAt(index)); |
215 } | 348 } |
216 | 349 |
217 gfx::Size ServiceButtonsView::GetPreferredSize() { | 350 gfx::Size ServiceButtonsView::GetPreferredSize() { |
218 // If there are no service buttons, hide this view. | 351 // If there are no service buttons, hide this view. |
219 if (model_->GetInstalledServiceCount() == 0) | 352 if (model_->GetInstalledServiceCount() == 0) |
220 return gfx::Size(); | 353 return gfx::Size(); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 // A delegate to respond to button presses and clicked links. | 477 // A delegate to respond to button presses and clicked links. |
345 Delegate* delegate_; | 478 Delegate* delegate_; |
346 | 479 |
347 // The icon of the extension. | 480 // The icon of the extension. |
348 views::ImageView* icon_; | 481 views::ImageView* icon_; |
349 | 482 |
350 // The title of the extension, which links to the CWS detailed description of | 483 // The title of the extension, which links to the CWS detailed description of |
351 // this extension. | 484 // this extension. |
352 views::Link* title_link_; | 485 views::Link* title_link_; |
353 | 486 |
354 // A throbber to display when the extension is being installed. | |
355 views::Throbber* throbber_; | |
356 | |
357 // The star rating of this extension. | 487 // The star rating of this extension. |
358 StarsView* stars_; | 488 StarsView* stars_; |
359 | 489 |
360 // A button to install the extension. | 490 // A button to install the extension. |
361 views::NativeTextButton* install_button_; | 491 ThrobberNativeTextButton* install_button_; |
362 | 492 |
363 DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsRowView); | 493 DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsRowView); |
364 }; | 494 }; |
365 | 495 |
366 SuggestedExtensionsRowView::SuggestedExtensionsRowView( | 496 SuggestedExtensionsRowView::SuggestedExtensionsRowView( |
367 const WebIntentPickerModel::SuggestedExtension* extension, | 497 const WebIntentPickerModel::SuggestedExtension* extension, |
368 Delegate* delegate) | 498 Delegate* delegate) |
369 : extension_(extension), | 499 : extension_(extension), |
370 delegate_(delegate) { | 500 delegate_(delegate) { |
371 SetLayoutManager(new SuggestedExtensionsLayout); | 501 SetLayoutManager(new SuggestedExtensionsLayout); |
372 | 502 |
373 icon_ = new views::ImageView(); | 503 icon_ = new views::ImageView(); |
374 icon_->SetImage(extension_->icon.ToSkBitmap()); | 504 icon_->SetImage(extension_->icon.ToSkBitmap()); |
375 AddChildView(icon_); | 505 AddChildView(icon_); |
376 | 506 |
377 string16 elided_title = ui::ElideText( | 507 string16 elided_title = ui::ElideText( |
378 extension_->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); | 508 extension_->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); |
379 title_link_ = new views::Link(elided_title); | 509 title_link_ = new views::Link(elided_title); |
380 title_link_->set_listener(this); | 510 title_link_->set_listener(this); |
381 AddChildView(title_link_); | 511 AddChildView(title_link_); |
382 | 512 |
383 throbber_ = new views::Throbber(60, true); | |
384 throbber_->SetVisible(false); | |
385 AddChildView(throbber_); | |
386 | |
387 stars_ = new StarsView(extension_->average_rating); | 513 stars_ = new StarsView(extension_->average_rating); |
388 AddChildView(stars_); | 514 AddChildView(stars_); |
389 | 515 |
390 install_button_= new views::NativeTextButton( | 516 install_button_= new ThrobberNativeTextButton( |
391 this, l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION)); | 517 this, l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION)); |
392 AddChildView(install_button_); | 518 AddChildView(install_button_); |
393 } | 519 } |
394 | 520 |
395 SuggestedExtensionsRowView::~SuggestedExtensionsRowView() { | 521 SuggestedExtensionsRowView::~SuggestedExtensionsRowView() { |
396 } | 522 } |
397 | 523 |
398 void SuggestedExtensionsRowView::ButtonPressed(views::Button* sender, | 524 void SuggestedExtensionsRowView::ButtonPressed(views::Button* sender, |
399 const views::Event& event) { | 525 const views::Event& event) { |
400 delegate_->OnExtensionInstallClicked(extension_->id); | 526 delegate_->OnExtensionInstallClicked(extension_->id); |
401 } | 527 } |
402 | 528 |
403 void SuggestedExtensionsRowView::LinkClicked(views::Link* source, | 529 void SuggestedExtensionsRowView::LinkClicked(views::Link* source, |
404 int event_flags) { | 530 int event_flags) { |
405 delegate_->OnExtensionLinkClicked(extension_->id); | 531 delegate_->OnExtensionLinkClicked(extension_->id); |
406 } | 532 } |
407 | 533 |
408 void SuggestedExtensionsRowView::StartThrobber() { | 534 void SuggestedExtensionsRowView::StartThrobber() { |
409 stars_->SetVisible(false); | 535 install_button_->StartThrobber(); |
410 install_button_->SetVisible(false); | 536 install_button_->SetText(string16()); |
411 throbber_->SetVisible(true); | |
412 throbber_->Start(); | |
413 Layout(); | |
414 } | 537 } |
415 | 538 |
416 void SuggestedExtensionsRowView::StopThrobber() { | 539 void SuggestedExtensionsRowView::StopThrobber() { |
417 stars_->SetVisible(true); | 540 install_button_->StopThrobber(); |
418 install_button_->SetVisible(true); | 541 install_button_->SetText( |
419 throbber_->SetVisible(false); | 542 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION)); |
420 throbber_->Stop(); | |
421 Layout(); | |
422 } | 543 } |
423 | 544 |
424 void SuggestedExtensionsRowView::OnEnabledChanged() { | 545 void SuggestedExtensionsRowView::OnEnabledChanged() { |
425 title_link_->SetEnabled(enabled()); | 546 title_link_->SetEnabled(enabled()); |
426 stars_->SetVisible(enabled()); | 547 stars_->SetEnabled(enabled()); |
427 install_button_->SetVisible(enabled()); | 548 install_button_->SetEnabled(enabled()); |
428 View::OnEnabledChanged(); | 549 View::OnEnabledChanged(); |
429 Layout(); | 550 Layout(); |
430 } | 551 } |
431 | 552 |
432 void SuggestedExtensionsRowView::PaintChildren(gfx::Canvas* canvas) { | 553 void SuggestedExtensionsRowView::PaintChildren(gfx::Canvas* canvas) { |
433 View::PaintChildren(canvas); | 554 View::PaintChildren(canvas); |
434 if (!enabled()) | 555 if (!enabled()) |
435 canvas->FillRect(GetLocalBounds(), kHalfOpacityWhite); | 556 canvas->FillRect(GetLocalBounds(), kHalfOpacityWhite); |
436 } | 557 } |
437 | 558 |
438 // SuggestedExtensionsView ----------------------------------------------------- | 559 // SuggestedExtensionsView ----------------------------------------------------- |
439 | 560 |
440 // A view that contains suggested extensions from the Chrome Web Store that | 561 // A view that contains suggested extensions from the Chrome Web Store that |
441 // provide an intent service matching the action/type pair. | 562 // provide an intent service matching the action/type pair. |
442 // This view also displays the "More suggestions" link which searches the | |
443 // Chrome Web Store for more extensions. | |
444 class SuggestedExtensionsView : public views::View { | 563 class SuggestedExtensionsView : public views::View { |
445 public: | 564 public: |
446 SuggestedExtensionsView(const WebIntentPickerModel* model, | 565 SuggestedExtensionsView(const WebIntentPickerModel* model, |
447 SuggestedExtensionsRowView::Delegate* delegate); | 566 SuggestedExtensionsRowView::Delegate* delegate); |
448 | 567 |
449 virtual ~SuggestedExtensionsView(); | 568 virtual ~SuggestedExtensionsView(); |
450 | 569 |
451 void Clear(); | 570 void Clear(); |
452 | 571 |
453 // Update the view to the new model data. | 572 // Update the view to the new model data. |
454 void Update(); | 573 void Update(); |
455 | 574 |
456 // Show the install throbber for the row containing |extension_id|. This | 575 // Show the install throbber for the row containing |extension_id|. This |
457 // function also hides hides and disables other buttons and links. | 576 // function also hides hides and disables other buttons and links. |
458 void StartThrobber(const string16& extension_id); | 577 void StartThrobber(const string16& extension_id); |
459 | 578 |
460 // Hide the install throbber. This function re-enables all buttons and links. | 579 // Hide the install throbber. This function re-enables all buttons and links. |
461 void StopThrobber(); | 580 void StopThrobber(); |
462 | 581 |
| 582 protected: |
| 583 virtual void OnEnabledChanged() OVERRIDE; |
| 584 |
463 private: | 585 private: |
464 const WebIntentPickerModel* model_; | 586 const WebIntentPickerModel* model_; |
465 SuggestedExtensionsRowView::Delegate* delegate_; | 587 SuggestedExtensionsRowView::Delegate* delegate_; |
466 | 588 |
467 DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsView); | 589 DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsView); |
468 }; | 590 }; |
469 | 591 |
470 SuggestedExtensionsView::SuggestedExtensionsView( | 592 SuggestedExtensionsView::SuggestedExtensionsView( |
471 const WebIntentPickerModel* model, | 593 const WebIntentPickerModel* model, |
472 SuggestedExtensionsRowView::Delegate* delegate) | 594 SuggestedExtensionsRowView::Delegate* delegate) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 | 633 |
512 void SuggestedExtensionsView::StopThrobber() { | 634 void SuggestedExtensionsView::StopThrobber() { |
513 for (size_t i = 0; i < model_->GetSuggestedExtensionCount(); ++i) { | 635 for (size_t i = 0; i < model_->GetSuggestedExtensionCount(); ++i) { |
514 SuggestedExtensionsRowView* row = | 636 SuggestedExtensionsRowView* row = |
515 static_cast<SuggestedExtensionsRowView*>(child_at(i)); | 637 static_cast<SuggestedExtensionsRowView*>(child_at(i)); |
516 row->SetEnabled(true); | 638 row->SetEnabled(true); |
517 row->StopThrobber(); | 639 row->StopThrobber(); |
518 } | 640 } |
519 } | 641 } |
520 | 642 |
| 643 void SuggestedExtensionsView::OnEnabledChanged() { |
| 644 EnableChildViews(this, enabled()); |
| 645 View::OnEnabledChanged(); |
| 646 } |
| 647 |
521 } // namespace | 648 } // namespace |
522 | 649 |
523 // WebIntentPickerViews -------------------------------------------------------- | 650 // WebIntentPickerViews -------------------------------------------------------- |
524 | 651 |
525 // Views implementation of WebIntentPicker. | 652 // Views implementation of WebIntentPicker. |
526 class WebIntentPickerViews : public views::ButtonListener, | 653 class WebIntentPickerViews : public views::ButtonListener, |
527 public views::DialogDelegate, | 654 public views::DialogDelegate, |
528 public views::LinkListener, | 655 public views::LinkListener, |
529 public WebIntentPicker, | 656 public WebIntentPicker, |
530 public WebIntentPickerModelObserver, | 657 public WebIntentPickerModelObserver, |
(...skipping 18 matching lines...) Expand all Loading... |
549 virtual views::View* GetContentsView() OVERRIDE; | 676 virtual views::View* GetContentsView() OVERRIDE; |
550 virtual int GetDialogButtons() const OVERRIDE; | 677 virtual int GetDialogButtons() const OVERRIDE; |
551 | 678 |
552 // LinkListener implementation. | 679 // LinkListener implementation. |
553 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; | 680 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; |
554 | 681 |
555 // WebIntentPicker implementation. | 682 // WebIntentPicker implementation. |
556 virtual void Close() OVERRIDE; | 683 virtual void Close() OVERRIDE; |
557 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE; | 684 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE; |
558 virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE; | 685 virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE; |
| 686 virtual void OnInlineDispositionWebContentsLoaded( |
| 687 content::WebContents* web_contents) OVERRIDE; |
559 | 688 |
560 // WebIntentPickerModelObserver implementation. | 689 // WebIntentPickerModelObserver implementation. |
561 virtual void OnModelChanged(WebIntentPickerModel* model) OVERRIDE; | 690 virtual void OnModelChanged(WebIntentPickerModel* model) OVERRIDE; |
562 virtual void OnFaviconChanged(WebIntentPickerModel* model, | 691 virtual void OnFaviconChanged(WebIntentPickerModel* model, |
563 size_t index) OVERRIDE; | 692 size_t index) OVERRIDE; |
564 virtual void OnExtensionIconChanged(WebIntentPickerModel* model, | 693 virtual void OnExtensionIconChanged(WebIntentPickerModel* model, |
565 const string16& extension_id) OVERRIDE; | 694 const string16& extension_id) OVERRIDE; |
566 virtual void OnInlineDisposition(WebIntentPickerModel* model, | 695 virtual void OnInlineDisposition(WebIntentPickerModel* model, |
567 const GURL& url) OVERRIDE; | 696 const GURL& url) OVERRIDE; |
568 | 697 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 | 743 |
615 // A weak pointer to the constrained window. | 744 // A weak pointer to the constrained window. |
616 ConstrainedWindowViews* window_; | 745 ConstrainedWindowViews* window_; |
617 | 746 |
618 // A weak pointer to the more suggestions link. | 747 // A weak pointer to the more suggestions link. |
619 views::Link* more_suggestions_link_; | 748 views::Link* more_suggestions_link_; |
620 | 749 |
621 // A weak pointer to the choose another service link. | 750 // A weak pointer to the choose another service link. |
622 views::Link* choose_another_service_link_; | 751 views::Link* choose_another_service_link_; |
623 | 752 |
| 753 // Set to true when displaying the inline disposition web contents. Used to |
| 754 // prevent laying out the inline disposition widgets twice. |
| 755 bool displaying_web_contents_; |
| 756 |
624 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerViews); | 757 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerViews); |
625 }; | 758 }; |
626 | 759 |
627 // static | 760 // static |
628 WebIntentPicker* WebIntentPicker::Create(Browser* browser, | 761 WebIntentPicker* WebIntentPicker::Create(Browser* browser, |
629 TabContentsWrapper* wrapper, | 762 TabContentsWrapper* wrapper, |
630 WebIntentPickerDelegate* delegate, | 763 WebIntentPickerDelegate* delegate, |
631 WebIntentPickerModel* model) { | 764 WebIntentPickerModel* model) { |
632 WebIntentPickerViews* picker = | 765 WebIntentPickerViews* picker = |
633 new WebIntentPickerViews(browser, wrapper, delegate, model); | 766 new WebIntentPickerViews(browser, wrapper, delegate, model); |
634 | 767 |
635 return picker; | 768 return picker; |
636 } | 769 } |
637 | 770 |
638 WebIntentPickerViews::WebIntentPickerViews(Browser* browser, | 771 WebIntentPickerViews::WebIntentPickerViews(Browser* browser, |
639 TabContentsWrapper* wrapper, | 772 TabContentsWrapper* wrapper, |
640 WebIntentPickerDelegate* delegate, | 773 WebIntentPickerDelegate* delegate, |
641 WebIntentPickerModel* model) | 774 WebIntentPickerModel* model) |
642 : delegate_(delegate), | 775 : delegate_(delegate), |
643 model_(model), | 776 model_(model), |
644 service_buttons_(NULL), | 777 service_buttons_(NULL), |
645 suggestions_label_(NULL), | 778 suggestions_label_(NULL), |
646 extensions_(NULL), | 779 extensions_(NULL), |
647 browser_(browser), | 780 browser_(browser), |
648 contents_(NULL), | 781 contents_(NULL), |
649 window_(NULL), | 782 window_(NULL), |
650 more_suggestions_link_(NULL), | 783 more_suggestions_link_(NULL), |
651 choose_another_service_link_(NULL) { | 784 choose_another_service_link_(NULL), |
| 785 displaying_web_contents_(false) { |
652 model_->set_observer(this); | 786 model_->set_observer(this); |
653 InitContents(); | 787 InitContents(); |
654 | 788 |
655 // Show the dialog. | 789 // Show the dialog. |
656 window_ = new ConstrainedWindowViews(wrapper, this); | 790 window_ = new ConstrainedWindowViews(wrapper, this); |
657 } | 791 } |
658 | 792 |
659 WebIntentPickerViews::~WebIntentPickerViews() { | 793 WebIntentPickerViews::~WebIntentPickerViews() { |
660 model_->set_observer(NULL); | 794 model_->set_observer(NULL); |
661 } | 795 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 | 851 |
718 void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) { | 852 void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) { |
719 service_buttons_->SetEnabled(true); | 853 service_buttons_->SetEnabled(true); |
720 extensions_->StopThrobber(); | 854 extensions_->StopThrobber(); |
721 more_suggestions_link_->SetEnabled(true); | 855 more_suggestions_link_->SetEnabled(true); |
722 contents_->Layout(); | 856 contents_->Layout(); |
723 | 857 |
724 // TODO(binji): What to display to user on failure? | 858 // TODO(binji): What to display to user on failure? |
725 } | 859 } |
726 | 860 |
727 void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) { | 861 void WebIntentPickerViews::OnInlineDispositionWebContentsLoaded( |
728 if (model->GetInstalledServiceCount() == 0) { | 862 content::WebContents* web_contents) { |
729 suggestions_label_->SetText(l10n_util::GetStringUTF16( | 863 if (displaying_web_contents_) |
730 IDS_INTENT_PICKER_GET_MORE_SERVICES_NONE_INSTALLED)); | 864 return; |
731 } else { | |
732 suggestions_label_->SetText( | |
733 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_GET_MORE_SERVICES)); | |
734 } | |
735 | |
736 service_buttons_->Update(); | |
737 extensions_->Update(); | |
738 contents_->Layout(); | |
739 SizeToContents(); | |
740 } | |
741 | |
742 void WebIntentPickerViews::OnFaviconChanged( | |
743 WebIntentPickerModel* model, size_t index) { | |
744 service_buttons_->Update(); | |
745 contents_->Layout(); | |
746 SizeToContents(); | |
747 } | |
748 | |
749 void WebIntentPickerViews::OnExtensionIconChanged( | |
750 WebIntentPickerModel* model, | |
751 const string16& extension_id) { | |
752 extensions_->Update(); | |
753 contents_->Layout(); | |
754 SizeToContents(); | |
755 } | |
756 | |
757 void WebIntentPickerViews::OnInlineDisposition( | |
758 WebIntentPickerModel* model, const GURL& url) { | |
759 WebContents* web_contents = WebContents::Create( | |
760 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); | |
761 inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate); | |
762 web_contents->SetDelegate(inline_disposition_delegate_.get()); | |
763 | |
764 const WebIntentPickerModel::InstalledService* service = | |
765 model->GetInstalledServiceWithURL(url); | |
766 DCHECK(service); | |
767 | |
768 // Must call this immediately after WebContents creation to avoid race | |
769 // with load. | |
770 delegate_->OnInlineDispositionWebContentsCreated(web_contents); | |
771 | |
772 TabContentsContainer* tab_contents_container = new TabContentsContainer; | |
773 | |
774 web_contents->GetController().LoadURL( | |
775 url, | |
776 content::Referrer(), | |
777 content::PAGE_TRANSITION_START_PAGE, | |
778 std::string()); | |
779 | 865 |
780 // Replace the picker with the inline disposition. | 866 // Replace the picker with the inline disposition. |
781 contents_->RemoveAllChildViews(true); | 867 contents_->RemoveAllChildViews(true); |
782 | 868 |
783 views::GridLayout* grid_layout = new views::GridLayout(contents_); | 869 views::GridLayout* grid_layout = new views::GridLayout(contents_); |
784 contents_->SetLayoutManager(grid_layout); | 870 contents_->SetLayoutManager(grid_layout); |
785 | 871 |
786 grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, | 872 grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, |
787 kContentAreaBorder, kContentAreaBorder); | 873 kContentAreaBorder, kContentAreaBorder); |
788 views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); | 874 views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); |
789 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, | 875 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, |
790 GridLayout::USE_PREF, 0, 0); // Icon. | 876 GridLayout::USE_PREF, 0, 0); // Icon. |
791 header_cs->AddPaddingColumn(0, 4); | 877 header_cs->AddPaddingColumn(0, 4); |
792 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, | 878 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, |
793 GridLayout::USE_PREF, 0, 0); // Title. | 879 GridLayout::USE_PREF, 0, 0); // Title. |
794 header_cs->AddPaddingColumn(0, 4); | 880 header_cs->AddPaddingColumn(0, 4); |
795 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, | 881 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, |
796 GridLayout::USE_PREF, 0, 0); // Link. | 882 GridLayout::USE_PREF, 0, 0); // Link. |
797 header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); | 883 header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); |
798 #if defined(USE_CLOSE_BUTTON) | 884 #if defined(USE_CLOSE_BUTTON) |
799 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, | 885 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, |
800 GridLayout::USE_PREF, 0, 0); // Close Button. | 886 GridLayout::USE_PREF, 0, 0); // Close Button. |
801 #endif | 887 #endif |
802 | 888 |
803 views::ColumnSet* full_cs = grid_layout->AddColumnSet(1); | 889 views::ColumnSet* full_cs = grid_layout->AddColumnSet(1); |
804 full_cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, | 890 full_cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, |
805 GridLayout::USE_PREF, 0, 0); | 891 GridLayout::USE_PREF, 0, 0); |
806 | 892 |
| 893 const WebIntentPickerModel::InstalledService* service = |
| 894 model_->GetInstalledServiceWithURL(model_->inline_disposition_url()); |
| 895 |
807 // Header row. | 896 // Header row. |
808 grid_layout->StartRow(0, 0); | 897 grid_layout->StartRow(0, 0); |
809 views::ImageView* icon = new views::ImageView(); | 898 views::ImageView* icon = new views::ImageView(); |
810 icon->SetImage(service->favicon.ToSkBitmap()); | 899 icon->SetImage(service->favicon.ToSkBitmap()); |
811 grid_layout->AddView(icon); | 900 grid_layout->AddView(icon); |
812 | 901 |
813 string16 elided_title = ui::ElideText( | 902 string16 elided_title = ui::ElideText( |
814 service->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); | 903 service->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); |
815 views::Label* title = new views::Label(elided_title); | 904 views::Label* title = new views::Label(elided_title); |
816 grid_layout->AddView(title); | 905 grid_layout->AddView(title); |
817 | 906 |
818 choose_another_service_link_ = new views::Link( | 907 choose_another_service_link_ = new views::Link( |
819 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE)); | 908 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE)); |
820 grid_layout->AddView(choose_another_service_link_); | 909 grid_layout->AddView(choose_another_service_link_); |
821 | 910 |
822 #if defined(USE_CLOSE_BUTTON) | 911 #if defined(USE_CLOSE_BUTTON) |
823 grid_layout->AddView(CreateCloseButton()); | 912 grid_layout->AddView(CreateCloseButton()); |
824 #endif | 913 #endif |
825 | 914 |
826 // Inline web contents row. | 915 // Inline web contents row. |
827 grid_layout->StartRow(0, 1); | 916 grid_layout->StartRow(0, 1); |
| 917 TabContentsContainer* tab_contents_container = new TabContentsContainer; |
828 grid_layout->AddView(tab_contents_container, 1, 1, GridLayout::CENTER, | 918 grid_layout->AddView(tab_contents_container, 1, 1, GridLayout::CENTER, |
829 GridLayout::CENTER, kDialogMinWidth, 140); | 919 GridLayout::CENTER, kDialogMinWidth, 140); |
830 | 920 |
831 // The contents can only be changed after the child is added to view | 921 // The contents can only be changed after the child is added to view |
832 // hierarchy. | 922 // hierarchy. |
833 tab_contents_container->ChangeWebContents(web_contents); | 923 tab_contents_container->ChangeWebContents(web_contents); |
834 | |
835 contents_->Layout(); | 924 contents_->Layout(); |
836 SizeToContents(); | 925 SizeToContents(); |
| 926 displaying_web_contents_ = true; |
| 927 } |
| 928 |
| 929 void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) { |
| 930 if (model->GetInstalledServiceCount() == 0) { |
| 931 suggestions_label_->SetText(l10n_util::GetStringUTF16( |
| 932 IDS_INTENT_PICKER_GET_MORE_SERVICES_NONE_INSTALLED)); |
| 933 } else { |
| 934 suggestions_label_->SetText( |
| 935 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_GET_MORE_SERVICES)); |
| 936 } |
| 937 |
| 938 service_buttons_->Update(); |
| 939 extensions_->Update(); |
| 940 contents_->Layout(); |
| 941 SizeToContents(); |
| 942 } |
| 943 |
| 944 void WebIntentPickerViews::OnFaviconChanged( |
| 945 WebIntentPickerModel* model, size_t index) { |
| 946 service_buttons_->Update(); |
| 947 contents_->Layout(); |
| 948 SizeToContents(); |
| 949 } |
| 950 |
| 951 void WebIntentPickerViews::OnExtensionIconChanged( |
| 952 WebIntentPickerModel* model, |
| 953 const string16& extension_id) { |
| 954 extensions_->Update(); |
| 955 contents_->Layout(); |
| 956 SizeToContents(); |
| 957 } |
| 958 |
| 959 void WebIntentPickerViews::OnInlineDisposition( |
| 960 WebIntentPickerModel* model, const GURL& url) { |
| 961 WebContents* web_contents = WebContents::Create( |
| 962 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); |
| 963 inline_disposition_delegate_.reset( |
| 964 new WebIntentInlineDispositionDelegate(this)); |
| 965 web_contents->SetDelegate(inline_disposition_delegate_.get()); |
| 966 |
| 967 const WebIntentPickerModel::InstalledService* service = |
| 968 model->GetInstalledServiceWithURL(url); |
| 969 DCHECK(service); |
| 970 |
| 971 // Must call this immediately after WebContents creation to avoid race |
| 972 // with load. |
| 973 delegate_->OnInlineDispositionWebContentsCreated(web_contents); |
| 974 web_contents->GetController().LoadURL( |
| 975 url, |
| 976 content::Referrer(), |
| 977 content::PAGE_TRANSITION_START_PAGE, |
| 978 std::string()); |
| 979 |
| 980 // Disable all buttons and show throbber. |
| 981 service_buttons_->SetEnabled(false); |
| 982 service_buttons_->StartThrobber(url); |
| 983 extensions_->SetEnabled(false); |
| 984 more_suggestions_link_->SetEnabled(false); |
| 985 contents_->Layout(); |
837 } | 986 } |
838 | 987 |
839 void WebIntentPickerViews::OnServiceButtonClicked( | 988 void WebIntentPickerViews::OnServiceButtonClicked( |
840 const WebIntentPickerModel::InstalledService& service) { | 989 const WebIntentPickerModel::InstalledService& service) { |
841 delegate_->OnServiceChosen(service.url, service.disposition); | 990 delegate_->OnServiceChosen(service.url, service.disposition); |
842 } | 991 } |
843 | 992 |
844 void WebIntentPickerViews::OnExtensionInstallClicked( | 993 void WebIntentPickerViews::OnExtensionInstallClicked( |
845 const string16& extension_id) { | 994 const string16& extension_id) { |
846 service_buttons_->SetEnabled(false); | 995 service_buttons_->SetEnabled(false); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 views::ImageButton* close_button = new views::ImageButton(this); | 1107 views::ImageButton* close_button = new views::ImageButton(this); |
959 close_button->SetImage(views::CustomButton::BS_NORMAL, | 1108 close_button->SetImage(views::CustomButton::BS_NORMAL, |
960 rb.GetBitmapNamed(IDR_CLOSE_BAR)); | 1109 rb.GetBitmapNamed(IDR_CLOSE_BAR)); |
961 close_button->SetImage(views::CustomButton::BS_HOT, | 1110 close_button->SetImage(views::CustomButton::BS_HOT, |
962 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); | 1111 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); |
963 close_button->SetImage(views::CustomButton::BS_PUSHED, | 1112 close_button->SetImage(views::CustomButton::BS_PUSHED, |
964 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); | 1113 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); |
965 return close_button; | 1114 return close_button; |
966 } | 1115 } |
967 #endif | 1116 #endif |
OLD | NEW |