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

Side by Side Diff: ui/views/controls/button/menu_button.cc

Issue 547303003: Keep reference view pressed while extension actions have a popup (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 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
OLDNEW
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 "ui/views/controls/button/menu_button.h" 5 #include "ui/views/controls/button/menu_button.h"
6 6
7 #include "base/strings/utf_string_conversions.h" 7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/accessibility/ax_view_state.h" 8 #include "ui/accessibility/ax_view_state.h"
9 #include "ui/base/dragdrop/drag_drop_types.h" 9 #include "ui/base/dragdrop/drag_drop_types.h"
10 #include "ui/base/l10n/l10n_util.h" 10 #include "ui/base/l10n/l10n_util.h"
(...skipping 30 matching lines...) Expand all
41 // 41 //
42 // MenuButton - constructors, destructors, initialization 42 // MenuButton - constructors, destructors, initialization
43 // 43 //
44 //////////////////////////////////////////////////////////////////////////////// 44 ////////////////////////////////////////////////////////////////////////////////
45 45
46 MenuButton::MenuButton(ButtonListener* listener, 46 MenuButton::MenuButton(ButtonListener* listener,
47 const base::string16& text, 47 const base::string16& text,
48 MenuButtonListener* menu_button_listener, 48 MenuButtonListener* menu_button_listener,
49 bool show_menu_marker) 49 bool show_menu_marker)
50 : LabelButton(listener, text), 50 : LabelButton(listener, text),
51 menu_visible_(false), 51 menus_visible_(0),
52 menu_offset_(kDefaultMenuOffsetX, kDefaultMenuOffsetY), 52 menu_offset_(kDefaultMenuOffsetX, kDefaultMenuOffsetY),
53 listener_(menu_button_listener), 53 listener_(menu_button_listener),
54 show_menu_marker_(show_menu_marker), 54 show_menu_marker_(show_menu_marker),
55 menu_marker_(ui::ResourceBundle::GetSharedInstance().GetImageNamed( 55 menu_marker_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
56 IDR_MENU_DROPARROW).ToImageSkia()), 56 IDR_MENU_DROPARROW).ToImageSkia()),
57 destroyed_flag_(NULL) { 57 destroyed_flag_(NULL) {
58 SetHorizontalAlignment(gfx::ALIGN_LEFT); 58 SetHorizontalAlignment(gfx::ALIGN_LEFT);
59 } 59 }
60 60
61 MenuButton::~MenuButton() { 61 MenuButton::~MenuButton() {
62 if (destroyed_flag_) 62 if (destroyed_flag_)
63 *destroyed_flag_ = true; 63 *destroyed_flag_ = true;
64 } 64 }
65 65
66 //////////////////////////////////////////////////////////////////////////////// 66 ////////////////////////////////////////////////////////////////////////////////
67 // 67 //
68 // MenuButton - Public APIs 68 // MenuButton - Public APIs
69 // 69 //
70 //////////////////////////////////////////////////////////////////////////////// 70 ////////////////////////////////////////////////////////////////////////////////
71 71
72 void MenuButton::AttachMenu() {
73 DCHECK_GE(menus_visible_, 0);
74 ++menus_visible_;
75 SetState(STATE_PRESSED);
76 }
77
78 void MenuButton::DetachMenu() {
79 --menus_visible_;
80 DCHECK_GE(menus_visible_, 0);
81 // If this was the last menu, we need to reset the state manually since we
82 // don't respond to mouse movement while menus are visible.
83 if (menus_visible_ == 0) {
84 // We set "normal" and not "hot" because the likelihood is that the mouse is
85 // now somewhere else (user clicked elsewhere on screen to close the menu
86 // or selected an item) and we will inevitably refresh the hot state
87 // in the event the mouse _is_ over the view.
88 SetState(STATE_NORMAL);
89 }
90 }
91
72 bool MenuButton::Activate() { 92 bool MenuButton::Activate() {
73 SetState(STATE_PRESSED); 93 SetState(STATE_PRESSED);
94
95 // We're already showing a menu (even if it might not be the main menu for
96 // this button). Don't show another one.
97 if (menu_visible())
98 return false;
99
74 if (listener_) { 100 if (listener_) {
75 gfx::Rect lb = GetLocalBounds(); 101 gfx::Rect lb = GetLocalBounds();
76 102
77 // The position of the menu depends on whether or not the locale is 103 // The position of the menu depends on whether or not the locale is
78 // right-to-left. 104 // right-to-left.
79 gfx::Point menu_position(lb.right(), lb.bottom()); 105 gfx::Point menu_position(lb.right(), lb.bottom());
80 if (base::i18n::IsRTL()) 106 if (base::i18n::IsRTL())
81 menu_position.set_x(lb.x()); 107 menu_position.set_x(lb.x());
82 108
83 View::ConvertPointToScreen(this, &menu_position); 109 View::ConvertPointToScreen(this, &menu_position);
84 if (base::i18n::IsRTL()) 110 if (base::i18n::IsRTL())
85 menu_position.Offset(-menu_offset_.x(), menu_offset_.y()); 111 menu_position.Offset(-menu_offset_.x(), menu_offset_.y());
86 else 112 else
87 menu_position.Offset(menu_offset_.x(), menu_offset_.y()); 113 menu_position.Offset(menu_offset_.x(), menu_offset_.y());
88 114
89 int max_x_coordinate = GetMaximumScreenXCoordinate(); 115 int max_x_coordinate = GetMaximumScreenXCoordinate();
90 if (max_x_coordinate && max_x_coordinate <= menu_position.x()) 116 if (max_x_coordinate && max_x_coordinate <= menu_position.x())
91 menu_position.set_x(max_x_coordinate - 1); 117 menu_position.set_x(max_x_coordinate - 1);
92 118
93 // We're about to show the menu from a mouse press. By showing from the 119 // We're about to show the menu from a mouse press. By showing from the
94 // mouse press event we block RootView in mouse dispatching. This also 120 // mouse press event we block RootView in mouse dispatching. This also
95 // appears to cause RootView to get a mouse pressed BEFORE the mouse 121 // appears to cause RootView to get a mouse pressed BEFORE the mouse
96 // release is seen, which means RootView sends us another mouse press no 122 // release is seen, which means RootView sends us another mouse press no
97 // matter where the user pressed. To force RootView to recalculate the 123 // matter where the user pressed. To force RootView to recalculate the
98 // mouse target during the mouse press we explicitly set the mouse handler 124 // mouse target during the mouse press we explicitly set the mouse handler
99 // to NULL. 125 // to NULL.
100 static_cast<internal::RootView*>(GetWidget()->GetRootView())-> 126 static_cast<internal::RootView*>(GetWidget()->GetRootView())->
101 SetMouseHandler(NULL); 127 SetMouseHandler(NULL);
102 128
103 menu_visible_ = true; 129 AttachMenu();
104 130
105 bool destroyed = false; 131 bool destroyed = false;
106 destroyed_flag_ = &destroyed; 132 destroyed_flag_ = &destroyed;
107 133
108 listener_->OnMenuButtonClicked(this, menu_position); 134 listener_->OnMenuButtonClicked(this, menu_position);
109 135
110 if (destroyed) { 136 if (destroyed) {
111 // The menu was deleted while showing. Don't attempt any processing. 137 // The menu was deleted while showing. Don't attempt any processing.
112 return false; 138 return false;
113 } 139 }
114 140
115 destroyed_flag_ = NULL; 141 destroyed_flag_ = NULL;
116 142
117 menu_visible_ = false; 143 DetachMenu();
118 menu_closed_time_ = TimeTicks::Now(); 144 menu_closed_time_ = TimeTicks::Now();
119 145
120 // Now that the menu has closed, we need to manually reset state to
121 // "normal" since the menu modal loop will have prevented normal
122 // mouse move messages from getting to this View. We set "normal"
123 // and not "hot" because the likelihood is that the mouse is now
124 // somewhere else (user clicked elsewhere on screen to close the menu
125 // or selected an item) and we will inevitably refresh the hot state
126 // in the event the mouse _is_ over the view.
127 SetState(STATE_NORMAL);
128
129 // We must return false here so that the RootView does not get stuck 146 // We must return false here so that the RootView does not get stuck
130 // sending all mouse pressed events to us instead of the appropriate 147 // sending all mouse pressed events to us instead of the appropriate
131 // target. 148 // target.
132 return false; 149 return false;
133 } 150 }
134 return true; 151 return true;
135 } 152 }
136 153
137 void MenuButton::OnPaint(gfx::Canvas* canvas) { 154 void MenuButton::OnPaint(gfx::Canvas* canvas) {
138 LabelButton::OnPaint(canvas); 155 LabelButton::OnPaint(canvas);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 // triggerable and there's a context menu). 201 // triggerable and there's a context menu).
185 if (GetDragOperations(event.location()) != ui::DragDropTypes::DRAG_NONE && 202 if (GetDragOperations(event.location()) != ui::DragDropTypes::DRAG_NONE &&
186 state() != STATE_DISABLED && !InDrag() && event.IsOnlyLeftMouseButton() && 203 state() != STATE_DISABLED && !InDrag() && event.IsOnlyLeftMouseButton() &&
187 HitTestPoint(event.location())) { 204 HitTestPoint(event.location())) {
188 Activate(); 205 Activate();
189 } else { 206 } else {
190 LabelButton::OnMouseReleased(event); 207 LabelButton::OnMouseReleased(event);
191 } 208 }
192 } 209 }
193 210
194 // The reason we override View::OnMouseExited is because we get this event when 211 bool MenuButton::ShouldRespondToMouseMovement() {
195 // we display the menu. If we don't override this method then 212 // We should ignore mouse events while a menu is showing so the proper state
196 // BaseButton::OnMouseExited will get the event and will set the button's state 213 // (usually STATE_PRESSED) remains.
197 // to STATE_NORMAL instead of keeping the state BM_PUSHED. This, in turn, will 214 return menus_visible_ == 0;
198 // cause the button to appear depressed while the menu is displayed.
199 void MenuButton::OnMouseExited(const ui::MouseEvent& event) {
200 if ((state_ != STATE_DISABLED) && (!menu_visible_) && (!InDrag())) {
201 SetState(STATE_NORMAL);
202 }
203 } 215 }
204 216
205 void MenuButton::OnGestureEvent(ui::GestureEvent* event) { 217 void MenuButton::OnGestureEvent(ui::GestureEvent* event) {
206 if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP && 218 if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP &&
207 !Activate()) { 219 !Activate()) {
208 // When |Activate()| returns |false|, it means that a menu is shown and 220 // When |Activate()| returns |false|, it means that a menu is shown and
209 // has handled the gesture event. So, there is no need to further process 221 // has handled the gesture event. So, there is no need to further process
210 // the gesture event here. 222 // the gesture event here.
211 return; 223 return;
212 } 224 }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 if (!GetWidget()) { 291 if (!GetWidget()) {
280 NOTREACHED(); 292 NOTREACHED();
281 return 0; 293 return 0;
282 } 294 }
283 295
284 gfx::Rect monitor_bounds = GetWidget()->GetWorkAreaBoundsInScreen(); 296 gfx::Rect monitor_bounds = GetWidget()->GetWorkAreaBoundsInScreen();
285 return monitor_bounds.right() - 1; 297 return monitor_bounds.right() - 1;
286 } 298 }
287 299
288 } // namespace views 300 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698