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 |