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 #include "chrome/browser/ui/gtk/download_shelf_gtk.h" | 5 #include "chrome/browser/ui/gtk/download_shelf_gtk.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "chrome/browser/download/download_item.h" | 9 #include "chrome/browser/download/download_item.h" |
| 10 #include "chrome/browser/download/download_item_model.h" | 10 #include "chrome/browser/download/download_item_model.h" |
| 11 #include "chrome/browser/download/download_util.h" | 11 #include "chrome/browser/download/download_util.h" |
| 12 #include "chrome/browser/ui/browser.h" | 12 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | 13 #include "chrome/browser/ui/gtk/browser_window_gtk.h" |
| 14 #include "chrome/browser/ui/gtk/custom_button.h" | 14 #include "chrome/browser/ui/gtk/custom_button.h" |
| 15 #include "chrome/browser/ui/gtk/download_item_gtk.h" | 15 #include "chrome/browser/ui/gtk/download_item_gtk.h" |
| 16 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" | 16 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" |
| 17 #include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h" | 17 #include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h" |
| 18 #include "chrome/browser/ui/gtk/gtk_theme_provider.h" | 18 #include "chrome/browser/ui/gtk/gtk_theme_provider.h" |
| 19 #include "chrome/browser/ui/gtk/gtk_util.h" | 19 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 20 #include "chrome/common/notification_service.h" | 20 #include "chrome/common/notification_service.h" |
| 21 #include "gfx/gtk_util.h" | 21 #include "gfx/gtk_util.h" |
| 22 #include "gfx/insets.h" | |
| 23 #include "gfx/point.h" | |
| 24 #include "gfx/rect.h" | |
| 22 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
| 23 #include "grit/theme_resources.h" | 26 #include "grit/theme_resources.h" |
| 24 #include "ui/base/l10n/l10n_util.h" | 27 #include "ui/base/l10n/l10n_util.h" |
| 25 #include "ui/base/resource/resource_bundle.h" | 28 #include "ui/base/resource/resource_bundle.h" |
| 26 | 29 |
| 27 namespace { | 30 namespace { |
| 28 | 31 |
| 29 // The height of the download items. | 32 // The height of the download items. |
| 30 const int kDownloadItemHeight = download_util::kSmallProgressIconSize; | 33 const int kDownloadItemHeight = download_util::kSmallProgressIconSize; |
| 31 | 34 |
| 32 // Padding between the download widgets. | 35 // Padding between the download widgets. |
| 33 const int kDownloadItemPadding = 10; | 36 const int kDownloadItemPadding = 10; |
| 34 | 37 |
| 35 // Padding between the top/bottom of the download widgets and the edge of the | 38 // Padding between the top/bottom of the download widgets and the edge of the |
| 36 // shelf. | 39 // shelf. |
| 37 const int kTopBottomPadding = 4; | 40 const int kTopBottomPadding = 4; |
| 38 | 41 |
| 39 // Padding between the left side of the shelf and the first download item. | 42 // Padding between the left side of the shelf and the first download item. |
| 40 const int kLeftPadding = 2; | 43 const int kLeftPadding = 2; |
| 41 | 44 |
| 42 // Padding between the right side of the shelf and the close button. | 45 // Padding between the right side of the shelf and the close button. |
| 43 const int kRightPadding = 10; | 46 const int kRightPadding = 10; |
| 44 | 47 |
| 45 // Speed of the shelf show/hide animation. | 48 // Speed of the shelf show/hide animation. |
| 46 const int kShelfAnimationDurationMs = 120; | 49 const int kShelfAnimationDurationMs = 120; |
| 47 | 50 |
| 51 // The time between when the user mouses out of the download shelf zone and | |
| 52 // when the shelf closes (when auto-close is enabled). | |
| 53 const int kAutoCloseDelayMs = 300; | |
| 54 | |
| 55 // The area to the top of the shelf that is considered part of its "zone". | |
| 56 const int kShelfAuraSize = 40; | |
| 57 | |
| 48 } // namespace | 58 } // namespace |
| 49 | 59 |
| 50 DownloadShelfGtk::DownloadShelfGtk(Browser* browser, GtkWidget* parent) | 60 DownloadShelfGtk::DownloadShelfGtk(Browser* browser, GtkWidget* parent) |
| 51 : browser_(browser), | 61 : browser_(browser), |
| 52 is_showing_(false), | 62 is_showing_(false), |
| 53 theme_provider_(GtkThemeProvider::GetFrom(browser->profile())) { | 63 theme_provider_(GtkThemeProvider::GetFrom(browser->profile())), |
| 64 close_on_mouse_out_(false), | |
| 65 mouse_in_shelf_(false), | |
| 66 auto_close_factory_(this) { | |
|
sky
2011/01/31 17:14:04
Do we only use the ALLOW_THIS_IN... macro on windo
Evan Stade
2011/01/31 18:59:49
yep
| |
| 54 // Logically, the shelf is a vbox that contains two children: a one pixel | 67 // Logically, the shelf is a vbox that contains two children: a one pixel |
| 55 // tall event box, which serves as the top border, and an hbox, which holds | 68 // tall event box, which serves as the top border, and an hbox, which holds |
| 56 // the download items and other shelf widgets (close button, show-all- | 69 // the download items and other shelf widgets (close button, show-all- |
| 57 // downloads link). | 70 // downloads link). |
| 58 // To make things pretty, we have to add a few more widgets. To get padding | 71 // To make things pretty, we have to add a few more widgets. To get padding |
| 59 // right, we stick the hbox in an alignment. We put that alignment in an | 72 // right, we stick the hbox in an alignment. We put that alignment in an |
| 60 // event box so we can color the background. | 73 // event box so we can color the background. |
| 61 | 74 |
| 62 // Create the top border. | 75 // Create the top border. |
| 63 top_border_ = gtk_event_box_new(); | 76 top_border_ = gtk_event_box_new(); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 } | 155 } |
| 143 | 156 |
| 144 DownloadShelfGtk::~DownloadShelfGtk() { | 157 DownloadShelfGtk::~DownloadShelfGtk() { |
| 145 for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin(); | 158 for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin(); |
| 146 iter != download_items_.end(); ++iter) { | 159 iter != download_items_.end(); ++iter) { |
| 147 delete *iter; | 160 delete *iter; |
| 148 } | 161 } |
| 149 | 162 |
| 150 shelf_.Destroy(); | 163 shelf_.Destroy(); |
| 151 items_hbox_.Destroy(); | 164 items_hbox_.Destroy(); |
| 152 } | 165 } |
|
sky
2011/01/31 17:14:04
Do you need SetCloseOnMouseOut(false) ?
Otherwise
Evan Stade
2011/01/31 18:59:49
I suppose I do
| |
| 153 | 166 |
| 154 void DownloadShelfGtk::AddDownload(BaseDownloadItemModel* download_model_) { | 167 void DownloadShelfGtk::AddDownload(BaseDownloadItemModel* download_model_) { |
| 155 download_items_.push_back(new DownloadItemGtk(this, download_model_)); | 168 download_items_.push_back(new DownloadItemGtk(this, download_model_)); |
| 156 Show(); | 169 Show(); |
| 157 } | 170 } |
| 158 | 171 |
| 159 bool DownloadShelfGtk::IsShowing() const { | 172 bool DownloadShelfGtk::IsShowing() const { |
| 160 return slide_widget_->IsShowing(); | 173 return slide_widget_->IsShowing(); |
| 161 } | 174 } |
| 162 | 175 |
| 163 bool DownloadShelfGtk::IsClosing() const { | 176 bool DownloadShelfGtk::IsClosing() const { |
| 164 return slide_widget_->IsClosing(); | 177 return slide_widget_->IsClosing(); |
| 165 } | 178 } |
| 166 | 179 |
| 167 void DownloadShelfGtk::Show() { | 180 void DownloadShelfGtk::Show() { |
| 168 slide_widget_->Open(); | 181 slide_widget_->Open(); |
| 169 browser_->UpdateDownloadShelfVisibility(true); | 182 browser_->UpdateDownloadShelfVisibility(true); |
| 183 CancelAutoClose(); | |
| 170 } | 184 } |
| 171 | 185 |
| 172 void DownloadShelfGtk::Close() { | 186 void DownloadShelfGtk::Close() { |
| 173 // When we are closing, we can vertically overlap the render view. Make sure | 187 // When we are closing, we can vertically overlap the render view. Make sure |
| 174 // we are on top. | 188 // we are on top. |
| 175 gdk_window_raise(shelf_.get()->window); | 189 gdk_window_raise(shelf_.get()->window); |
| 176 slide_widget_->Close(); | 190 slide_widget_->Close(); |
| 177 browser_->UpdateDownloadShelfVisibility(false); | 191 browser_->UpdateDownloadShelfVisibility(false); |
| 192 SetCloseOnMouseOut(false); | |
| 178 } | 193 } |
| 179 | 194 |
| 180 Browser* DownloadShelfGtk::browser() const { | 195 Browser* DownloadShelfGtk::browser() const { |
| 181 return browser_; | 196 return browser_; |
| 182 } | 197 } |
| 183 | 198 |
| 184 void DownloadShelfGtk::Closed() { | 199 void DownloadShelfGtk::Closed() { |
| 185 // When the close animation is complete, remove all completed downloads. | 200 // When the close animation is complete, remove all completed downloads. |
| 186 size_t i = 0; | 201 size_t i = 0; |
| 187 while (i < download_items_.size()) { | 202 while (i < download_items_.size()) { |
| 188 DownloadItem* download = download_items_[i]->get_download(); | 203 DownloadItem* download = download_items_[i]->get_download(); |
| 189 bool is_transfer_done = download->state() == DownloadItem::COMPLETE || | 204 bool is_transfer_done = download->state() == DownloadItem::COMPLETE || |
| 190 download->state() == DownloadItem::CANCELLED; | 205 download->state() == DownloadItem::CANCELLED; |
| 191 if (is_transfer_done && | 206 if (is_transfer_done && |
| 192 download->safety_state() != DownloadItem::DANGEROUS) { | 207 download->safety_state() != DownloadItem::DANGEROUS) { |
| 193 RemoveDownloadItem(download_items_[i]); | 208 RemoveDownloadItem(download_items_[i]); |
| 194 } else { | 209 } else { |
| 210 // We set all remaining items as "opened", so that the shelf will auto- | |
| 211 // close in the future without the user clicking on them. | |
| 212 download->set_opened(true); | |
| 195 ++i; | 213 ++i; |
| 196 } | 214 } |
| 197 } | 215 } |
| 198 } | 216 } |
| 199 | 217 |
| 200 void DownloadShelfGtk::Observe(NotificationType type, | 218 void DownloadShelfGtk::Observe(NotificationType type, |
| 201 const NotificationSource& source, | 219 const NotificationSource& source, |
| 202 const NotificationDetails& details) { | 220 const NotificationDetails& details) { |
| 203 if (type == NotificationType::BROWSER_THEME_CHANGED) { | 221 if (type == NotificationType::BROWSER_THEME_CHANGED) { |
| 204 GdkColor color = theme_provider_->GetGdkColor( | 222 GdkColor color = theme_provider_->GetGdkColor( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 void DownloadShelfGtk::RemoveDownloadItem(DownloadItemGtk* download_item) { | 257 void DownloadShelfGtk::RemoveDownloadItem(DownloadItemGtk* download_item) { |
| 240 DCHECK(download_item); | 258 DCHECK(download_item); |
| 241 std::vector<DownloadItemGtk*>::iterator i = | 259 std::vector<DownloadItemGtk*>::iterator i = |
| 242 find(download_items_.begin(), download_items_.end(), download_item); | 260 find(download_items_.begin(), download_items_.end(), download_item); |
| 243 DCHECK(i != download_items_.end()); | 261 DCHECK(i != download_items_.end()); |
| 244 download_items_.erase(i); | 262 download_items_.erase(i); |
| 245 delete download_item; | 263 delete download_item; |
| 246 if (download_items_.empty()) { | 264 if (download_items_.empty()) { |
| 247 slide_widget_->CloseWithoutAnimation(); | 265 slide_widget_->CloseWithoutAnimation(); |
| 248 browser_->UpdateDownloadShelfVisibility(false); | 266 browser_->UpdateDownloadShelfVisibility(false); |
| 267 } else { | |
| 268 AutoCloseIfPossible(); | |
| 249 } | 269 } |
| 250 } | 270 } |
| 251 | 271 |
| 252 GtkWidget* DownloadShelfGtk::GetHBox() const { | 272 GtkWidget* DownloadShelfGtk::GetHBox() const { |
| 253 return items_hbox_.get(); | 273 return items_hbox_.get(); |
| 254 } | 274 } |
| 255 | 275 |
| 256 void DownloadShelfGtk::MaybeShowMoreDownloadItems() { | 276 void DownloadShelfGtk::MaybeShowMoreDownloadItems() { |
| 257 // Show all existing download items. It'll trigger "size-allocate" signal, | 277 // Show all existing download items. It'll trigger "size-allocate" signal, |
| 258 // which will hide download items that don't have enough space to show. | 278 // which will hide download items that don't have enough space to show. |
| 259 gtk_widget_show_all(items_hbox_.get()); | 279 gtk_widget_show_all(items_hbox_.get()); |
| 260 } | 280 } |
| 261 | 281 |
| 262 void DownloadShelfGtk::OnButtonClick(GtkWidget* button) { | 282 void DownloadShelfGtk::OnButtonClick(GtkWidget* button) { |
| 263 if (button == close_button_->widget()) { | 283 if (button == close_button_->widget()) { |
| 264 Close(); | 284 Close(); |
| 265 } else { | 285 } else { |
| 266 // The link button was clicked. | 286 // The link button was clicked. |
| 267 browser_->ShowDownloadsTab(); | 287 browser_->ShowDownloadsTab(); |
| 268 } | 288 } |
| 269 } | 289 } |
| 290 | |
| 291 void DownloadShelfGtk::AutoCloseIfPossible() { | |
| 292 for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin(); | |
| 293 iter != download_items_.end(); ++iter) { | |
| 294 if (!(*iter)->get_download()->opened()) | |
| 295 return; | |
| 296 } | |
| 297 | |
| 298 SetCloseOnMouseOut(true); | |
| 299 } | |
| 300 | |
| 301 void DownloadShelfGtk::CancelAutoClose() { | |
| 302 SetCloseOnMouseOut(false); | |
| 303 auto_close_factory_.RevokeAll(); | |
| 304 } | |
| 305 | |
| 306 void DownloadShelfGtk::ItemOpened() { | |
| 307 AutoCloseIfPossible(); | |
| 308 } | |
| 309 | |
| 310 void DownloadShelfGtk::SetCloseOnMouseOut(bool close) { | |
| 311 if (close_on_mouse_out_ == close) | |
| 312 return; | |
| 313 | |
| 314 close_on_mouse_out_ = close; | |
| 315 mouse_in_shelf_ = close; | |
| 316 if (close) | |
| 317 MessageLoopForUI::current()->AddObserver(this); | |
| 318 else | |
| 319 MessageLoopForUI::current()->RemoveObserver(this); | |
| 320 } | |
| 321 | |
| 322 void DownloadShelfGtk::WillProcessEvent(GdkEvent* event) { | |
| 323 } | |
| 324 | |
| 325 void DownloadShelfGtk::DidProcessEvent(GdkEvent* event) { | |
| 326 gfx::Point cursor_screen_coords; | |
| 327 | |
| 328 switch (event->type) { | |
| 329 case GDK_MOTION_NOTIFY: | |
| 330 cursor_screen_coords = | |
| 331 gfx::Point(event->motion.x_root, event->motion.y_root); | |
| 332 break; | |
| 333 case GDK_LEAVE_NOTIFY: | |
| 334 cursor_screen_coords = | |
| 335 gfx::Point(event->crossing.x_root, event->crossing.y_root); | |
| 336 break; | |
| 337 default: | |
| 338 return; | |
| 339 } | |
| 340 | |
| 341 bool mouse_in_shelf = IsCursorInShelfZone(cursor_screen_coords); | |
| 342 if (mouse_in_shelf == mouse_in_shelf_) | |
| 343 return; | |
| 344 mouse_in_shelf_ = mouse_in_shelf; | |
| 345 | |
| 346 if (mouse_in_shelf) | |
| 347 MouseEnteredShelf(); | |
| 348 else | |
| 349 MouseLeftShelf(); | |
| 350 } | |
| 351 | |
| 352 bool DownloadShelfGtk::IsCursorInShelfZone( | |
| 353 const gfx::Point& cursor_screen_coords) { | |
| 354 gfx::Rect bounds(gtk_util::GetWidgetScreenPosition(shelf_.get()), | |
| 355 gfx::Size(shelf_.get()->allocation.width, | |
| 356 shelf_.get()->allocation.height)); | |
| 357 | |
| 358 // Negative insets expand the rectangle. We only expand the top. | |
| 359 bounds.Inset(gfx::Insets(-kShelfAuraSize, 0, 0, 0)); | |
| 360 | |
| 361 return bounds.Contains(cursor_screen_coords); | |
| 362 } | |
| 363 | |
| 364 void DownloadShelfGtk::MouseLeftShelf() { | |
| 365 DCHECK(close_on_mouse_out_); | |
| 366 | |
| 367 MessageLoop::current()->PostDelayedTask( | |
| 368 FROM_HERE, | |
| 369 auto_close_factory_.NewRunnableMethod(&DownloadShelfGtk::Close), | |
| 370 kAutoCloseDelayMs); | |
| 371 } | |
| 372 | |
| 373 void DownloadShelfGtk::MouseEnteredShelf() { | |
| 374 auto_close_factory_.RevokeAll(); | |
| 375 } | |
| OLD | NEW |