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

Side by Side Diff: chrome/browser/ui/gtk/download_shelf_gtk.cc

Issue 6249022: Make the gtk download shelf autoclose on mouse out. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698