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 "ui/views/controls/menu/menu_controller.h" | 5 #include "ui/views/controls/menu/menu_controller.h" |
6 | 6 |
7 #include "base/i18n/case_conversion.h" | 7 #include "base/i18n/case_conversion.h" |
8 #include "base/i18n/rtl.h" | 8 #include "base/i18n/rtl.h" |
9 #include "base/time.h" | 9 #include "base/time.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
11 #include "ui/base/dragdrop/os_exchange_data.h" | 11 #include "ui/base/dragdrop/os_exchange_data.h" |
12 #include "ui/base/events.h" | 12 #include "ui/base/events.h" |
13 #include "ui/base/keycodes/keyboard_codes.h" | 13 #include "ui/base/keycodes/keyboard_codes.h" |
14 #include "ui/base/l10n/l10n_util.h" | 14 #include "ui/base/l10n/l10n_util.h" |
15 #include "ui/gfx/canvas_skia.h" | 15 #include "ui/gfx/canvas_skia.h" |
16 #include "ui/gfx/screen.h" | 16 #include "ui/gfx/screen.h" |
17 #include "ui/views/controls/button/menu_button.h" | 17 #include "ui/views/controls/button/menu_button.h" |
18 #include "ui/views/controls/menu/menu_controller_delegate.h" | 18 #include "ui/views/controls/menu/menu_controller_delegate.h" |
19 #include "ui/views/controls/menu/menu_scroll_view_container.h" | 19 #include "ui/views/controls/menu/menu_scroll_view_container.h" |
20 #include "ui/views/controls/menu/submenu_view.h" | 20 #include "ui/views/controls/menu/submenu_view.h" |
21 #include "ui/views/drag_utils.h" | 21 #include "ui/views/drag_utils.h" |
22 #include "ui/views/view_constants.h" | 22 #include "ui/views/view_constants.h" |
23 #include "ui/views/views_delegate.h" | 23 #include "ui/views/views_delegate.h" |
24 #include "ui/views/widget/root_view.h" | 24 #include "ui/views/widget/root_view.h" |
25 #include "ui/views/widget/widget.h" | 25 #include "ui/views/widget/widget.h" |
26 | 26 |
27 #if defined(USE_AURA) | 27 #if defined(USE_AURA) |
28 #include "ui/aura/client/dispatcher_client.h" | 28 #include "ui/aura/client/dispatcher_client.h" |
29 #include "ui/aura/env.h" | 29 #include "ui/aura/env.h" |
| 30 #include "ui/aura/event.h" |
30 #include "ui/aura/root_window.h" | 31 #include "ui/aura/root_window.h" |
31 #elif defined(TOOLKIT_USES_GTK) | 32 #elif defined(TOOLKIT_USES_GTK) |
32 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" | 33 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" |
33 #endif | 34 #endif |
34 | 35 |
35 using base::Time; | 36 #if defined(USE_AURA) && defined(USE_X11) |
| 37 #include <X11/Xlib.h> |
| 38 #endif |
| 39 |
36 using base::TimeDelta; | 40 using base::TimeDelta; |
37 using ui::OSExchangeData; | 41 using ui::OSExchangeData; |
38 | 42 |
39 // Period of the scroll timer (in milliseconds). | 43 // Period of the scroll timer (in milliseconds). |
40 static const int kScrollTimerMS = 30; | 44 static const int kScrollTimerMS = 30; |
41 | 45 |
42 // Delay, in ms, between when menus are selected are moused over and the menu | 46 // Delay, in ms, between when menus are selected are moused over and the menu |
43 // appears. | 47 // appears. |
44 static const int kShowDelay = 400; | 48 static const int kShowDelay = 400; |
45 | 49 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 if (!part.is_scroll()) { | 160 if (!part.is_scroll()) { |
157 StopScrolling(); | 161 StopScrolling(); |
158 return; | 162 return; |
159 } | 163 } |
160 DCHECK(part.submenu); | 164 DCHECK(part.submenu); |
161 SubmenuView* new_menu = part.submenu; | 165 SubmenuView* new_menu = part.submenu; |
162 bool new_is_up = (part.type == MenuController::MenuPart::SCROLL_UP); | 166 bool new_is_up = (part.type == MenuController::MenuPart::SCROLL_UP); |
163 if (new_menu == submenu_ && is_scrolling_up_ == new_is_up) | 167 if (new_menu == submenu_ && is_scrolling_up_ == new_is_up) |
164 return; | 168 return; |
165 | 169 |
166 start_scroll_time_ = Time::Now(); | 170 start_scroll_time_ = base::Time::Now(); |
167 start_y_ = part.submenu->GetVisibleBounds().y(); | 171 start_y_ = part.submenu->GetVisibleBounds().y(); |
168 submenu_ = new_menu; | 172 submenu_ = new_menu; |
169 is_scrolling_up_ = new_is_up; | 173 is_scrolling_up_ = new_is_up; |
170 | 174 |
171 if (!scrolling_timer_.IsRunning()) { | 175 if (!scrolling_timer_.IsRunning()) { |
172 scrolling_timer_.Start(FROM_HERE, | 176 scrolling_timer_.Start(FROM_HERE, |
173 TimeDelta::FromMilliseconds(kScrollTimerMS), | 177 TimeDelta::FromMilliseconds(kScrollTimerMS), |
174 this, &MenuScrollTask::Run); | 178 this, &MenuScrollTask::Run); |
175 } | 179 } |
176 } | 180 } |
177 | 181 |
178 void StopScrolling() { | 182 void StopScrolling() { |
179 if (scrolling_timer_.IsRunning()) { | 183 if (scrolling_timer_.IsRunning()) { |
180 scrolling_timer_.Stop(); | 184 scrolling_timer_.Stop(); |
181 submenu_ = NULL; | 185 submenu_ = NULL; |
182 } | 186 } |
183 } | 187 } |
184 | 188 |
185 // The menu being scrolled. Returns null if not scrolling. | 189 // The menu being scrolled. Returns null if not scrolling. |
186 SubmenuView* submenu() const { return submenu_; } | 190 SubmenuView* submenu() const { return submenu_; } |
187 | 191 |
188 private: | 192 private: |
189 void Run() { | 193 void Run() { |
190 DCHECK(submenu_); | 194 DCHECK(submenu_); |
191 gfx::Rect vis_rect = submenu_->GetVisibleBounds(); | 195 gfx::Rect vis_rect = submenu_->GetVisibleBounds(); |
192 const int delta_y = static_cast<int>( | 196 const int delta_y = static_cast<int>( |
193 (Time::Now() - start_scroll_time_).InMilliseconds() * | 197 (base::Time::Now() - start_scroll_time_).InMilliseconds() * |
194 pixels_per_second_ / 1000); | 198 pixels_per_second_ / 1000); |
195 vis_rect.set_y(is_scrolling_up_ ? | 199 vis_rect.set_y(is_scrolling_up_ ? |
196 std::max(0, start_y_ - delta_y) : | 200 std::max(0, start_y_ - delta_y) : |
197 std::min(submenu_->height() - vis_rect.height(), start_y_ + delta_y)); | 201 std::min(submenu_->height() - vis_rect.height(), start_y_ + delta_y)); |
198 submenu_->ScrollRectToVisible(vis_rect); | 202 submenu_->ScrollRectToVisible(vis_rect); |
199 } | 203 } |
200 | 204 |
201 // SubmenuView being scrolled. | 205 // SubmenuView being scrolled. |
202 SubmenuView* submenu_; | 206 SubmenuView* submenu_; |
203 | 207 |
204 // Direction scrolling. | 208 // Direction scrolling. |
205 bool is_scrolling_up_; | 209 bool is_scrolling_up_; |
206 | 210 |
207 // Timer to periodically scroll. | 211 // Timer to periodically scroll. |
208 base::RepeatingTimer<MenuScrollTask> scrolling_timer_; | 212 base::RepeatingTimer<MenuScrollTask> scrolling_timer_; |
209 | 213 |
210 // Time we started scrolling at. | 214 // Time we started scrolling at. |
211 Time start_scroll_time_; | 215 base::Time start_scroll_time_; |
212 | 216 |
213 // How many pixels to scroll per second. | 217 // How many pixels to scroll per second. |
214 int pixels_per_second_; | 218 int pixels_per_second_; |
215 | 219 |
216 // Y-coordinate of submenu_view_ when scrolling started. | 220 // Y-coordinate of submenu_view_ when scrolling started. |
217 int start_y_; | 221 int start_y_; |
218 | 222 |
219 DISALLOW_COPY_AND_ASSIGN(MenuScrollTask); | 223 DISALLOW_COPY_AND_ASSIGN(MenuScrollTask); |
220 }; | 224 }; |
221 | 225 |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 return; // Ignore presses on scroll buttons. | 782 return; // Ignore presses on scroll buttons. |
779 | 783 |
780 if (part.type == MenuPart::NONE || | 784 if (part.type == MenuPart::NONE || |
781 (part.type == MenuPart::MENU_ITEM && part.menu && | 785 (part.type == MenuPart::MENU_ITEM && part.menu && |
782 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) { | 786 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) { |
783 // Mouse wasn't pressed over any menu, or the active menu, cancel. | 787 // Mouse wasn't pressed over any menu, or the active menu, cancel. |
784 | 788 |
785 // We're going to close and we own the mouse capture. We need to repost the | 789 // We're going to close and we own the mouse capture. We need to repost the |
786 // mouse down, otherwise the window the user clicked on won't get the | 790 // mouse down, otherwise the window the user clicked on won't get the |
787 // event. | 791 // event. |
788 #if defined(OS_WIN) && !defined(USE_AURA) | 792 #if defined(OS_WIN) || defined(USE_AURA) |
789 RepostEvent(source, event); | 793 RepostEvent(source, event); |
790 // NOTE: not reposting on linux seems fine. | 794 // NOTE: not reposting on linux seems fine. |
791 #endif | 795 #endif |
792 | 796 |
793 // And close. | 797 // And close. |
794 ExitType exit_type = EXIT_ALL; | 798 ExitType exit_type = EXIT_ALL; |
795 if (!menu_stack_.empty()) { | 799 if (!menu_stack_.empty()) { |
796 // We're running nested menus. Only exit all if the mouse wasn't over one | 800 // We're running nested menus. Only exit all if the mouse wasn't over one |
797 // of the menus from the last run. | 801 // of the menus from the last run. |
798 gfx::Point screen_loc(event.location()); | 802 gfx::Point screen_loc(event.location()); |
(...skipping 1030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1829 } | 1833 } |
1830 | 1834 |
1831 // If no mnemonics found, look at first character of titles. | 1835 // If no mnemonics found, look at first character of titles. |
1832 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic); | 1836 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic); |
1833 if (details.first_match != -1) | 1837 if (details.first_match != -1) |
1834 return AcceptOrSelect(item, details); | 1838 return AcceptOrSelect(item, details); |
1835 | 1839 |
1836 return false; | 1840 return false; |
1837 } | 1841 } |
1838 | 1842 |
1839 #if defined(OS_WIN) && !defined(USE_AURA) | 1843 #if defined(OS_WIN) |
1840 void MenuController::RepostEvent(SubmenuView* source, | 1844 void MenuController::RepostEvent(SubmenuView* source, |
1841 const LocatedEvent& event) { | 1845 const LocatedEvent& event) { |
1842 if (!state_.item) { | 1846 if (!state_.item) { |
1843 // We some times get an event after closing all the menus. Ignore it. | 1847 // We some times get an event after closing all the menus. Ignore it. |
1844 // Make sure the menu is in fact not visible. If the menu is visible, then | 1848 // Make sure the menu is in fact not visible. If the menu is visible, then |
1845 // we're in a bad state where we think the menu isn't visibile but it is. | 1849 // we're in a bad state where we think the menu isn't visibile but it is. |
1846 DCHECK(!source->GetWidget()->IsVisible()); | 1850 DCHECK(!source->GetWidget()->IsVisible()); |
1847 return; | 1851 return; |
1848 } | 1852 } |
1849 | 1853 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 if (in_client_area) { | 1901 if (in_client_area) { |
1898 PostMessage(window, event_type, event.native_event().wParam, | 1902 PostMessage(window, event_type, event.native_event().wParam, |
1899 MAKELPARAM(window_x, window_y)); | 1903 MAKELPARAM(window_x, window_y)); |
1900 } else { | 1904 } else { |
1901 PostMessage(window, event_type, nc_hit_result, | 1905 PostMessage(window, event_type, nc_hit_result, |
1902 MAKELPARAM(screen_loc.x(), screen_loc.y())); | 1906 MAKELPARAM(screen_loc.x(), screen_loc.y())); |
1903 } | 1907 } |
1904 } | 1908 } |
1905 } | 1909 } |
1906 } | 1910 } |
1907 #endif // defined(OS_WIN) | 1911 #elif defined(USE_AURA) |
| 1912 void MenuController::RepostEvent(SubmenuView* source, |
| 1913 const LocatedEvent& event) { |
| 1914 if (!state_.item) { |
| 1915 // We some times get an event after closing all the menus. Ignore it. |
| 1916 // Make sure the menu is in fact not visible. If the menu is visible, then |
| 1917 // we're in a bad state where we think the menu isn't visibile but it is. |
| 1918 DCHECK(!source->GetWidget()->IsVisible()); |
| 1919 return; |
| 1920 } |
| 1921 |
| 1922 // Release the capture. |
| 1923 SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu(); |
| 1924 submenu->ReleaseCapture(); |
| 1925 |
| 1926 gfx::Point screen_loc(event.location()); |
| 1927 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); |
| 1928 |
| 1929 XEvent xevent; |
| 1930 xevent.type = ButtonPress; |
| 1931 xevent.xbutton.x = screen_loc.x(); |
| 1932 xevent.xbutton.y = screen_loc.y(); |
| 1933 xevent.xbutton.state = 0; |
| 1934 xevent.xbutton.same_screen = True; |
| 1935 int flags = event.flags(); |
| 1936 if (flags & ui::EF_LEFT_MOUSE_BUTTON) |
| 1937 xevent.xbutton.button = 1; |
| 1938 else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) |
| 1939 xevent.xbutton.button = 2; |
| 1940 else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) |
| 1941 xevent.xbutton.button = 3; |
| 1942 else |
| 1943 return; |
| 1944 |
| 1945 aura::RootWindow::GetInstance()->PostNativeEvent(&xevent); |
| 1946 } |
| 1947 #endif // defined(USE_AURA) |
1908 | 1948 |
1909 void MenuController::SetDropMenuItem( | 1949 void MenuController::SetDropMenuItem( |
1910 MenuItemView* new_target, | 1950 MenuItemView* new_target, |
1911 MenuDelegate::DropPosition new_position) { | 1951 MenuDelegate::DropPosition new_position) { |
1912 if (new_target == drop_target_ && new_position == drop_position_) | 1952 if (new_target == drop_target_ && new_position == drop_position_) |
1913 return; | 1953 return; |
1914 | 1954 |
1915 if (drop_target_) { | 1955 if (drop_target_) { |
1916 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem( | 1956 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem( |
1917 NULL, MenuDelegate::DROP_NONE); | 1957 NULL, MenuDelegate::DROP_NONE); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2044 (!pending_state_.item->HasSubmenu() || | 2084 (!pending_state_.item->HasSubmenu() || |
2045 !pending_state_.item->GetSubmenu()->IsShowing())) { | 2085 !pending_state_.item->GetSubmenu()->IsShowing())) { |
2046 // On exit if the user hasn't selected an item with a submenu, move the | 2086 // On exit if the user hasn't selected an item with a submenu, move the |
2047 // selection back to the parent menu item. | 2087 // selection back to the parent menu item. |
2048 SetSelection(pending_state_.item->GetParentMenuItem(), | 2088 SetSelection(pending_state_.item->GetParentMenuItem(), |
2049 SELECTION_OPEN_SUBMENU); | 2089 SELECTION_OPEN_SUBMENU); |
2050 } | 2090 } |
2051 } | 2091 } |
2052 | 2092 |
2053 } // namespace views | 2093 } // namespace views |
OLD | NEW |