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 3 // found in the LICENSE file. 4 5 #include "ui/views/controls/menu/menu_host.h" 6 7 #include "base/debug/trace_event.h" 8 #include "ui/gfx/path.h" 9 #include "ui/native_theme/native_theme.h" 10 #include "ui/views/controls/menu/menu_controller.h" 11 #include "ui/views/controls/menu/menu_host_root_view.h" 12 #include "ui/views/controls/menu/menu_item_view.h" 13 #include "ui/views/controls/menu/menu_scroll_view_container.h" 14 #include "ui/views/controls/menu/submenu_view.h" 15 #include "ui/views/round_rect_painter.h" 16 #include "ui/views/widget/native_widget_private.h" 17 #include "ui/views/widget/widget.h" 18 19 #if defined(USE_AURA) 20 #include "ui/views/corewm/shadow_types.h" 21 #endif 22 23 namespace views { 24 25 //////////////////////////////////////////////////////////////////////////////// 26 // MenuHost, public: 27 28 MenuHost::MenuHost(SubmenuView* submenu) 29 : submenu_(submenu), 30 destroying_(false), 31 ignore_capture_lost_(false) { 32 } 33 34 MenuHost::~MenuHost() { 35 } 36 37 void MenuHost::InitMenuHost(Widget* parent, 38 const gfx::Rect& bounds, 39 View* contents_view, 40 bool do_capture) { 41 TRACE_EVENT0("views", "MenuHost::InitMenuHost"); 42 Widget::InitParams params(Widget::InitParams::TYPE_MENU); 43 const MenuController* menu_controller = 44 submenu_->GetMenuItem()->GetMenuController(); 45 const MenuConfig& menu_config = submenu_->GetMenuItem()->GetMenuConfig(); 46 bool rounded_border = menu_controller && menu_config.corner_radius > 0; 47 bool bubble_border = submenu_->GetScrollViewContainer() && 48 submenu_->GetScrollViewContainer()->HasBubbleBorder(); 49 params.has_dropshadow = !bubble_border; 50 params.opacity = (bubble_border || rounded_border) ? 51 Widget::InitParams::TRANSLUCENT_WINDOW : 52 Widget::InitParams::OPAQUE_WINDOW; 53 params.parent = parent ? parent->GetNativeView() : NULL; 54 params.bounds = bounds; 55 Init(params); 56 57 #if defined(USE_AURA) 58 if (bubble_border) 59 SetShadowType(GetNativeView(), views::corewm::SHADOW_TYPE_NONE); 60 #endif 61 62 SetContentsView(contents_view); 63 if (bubble_border || rounded_border) 64 SetOpacity(0); 65 ShowMenuHost(do_capture); 66 } 67 68 bool MenuHost::IsMenuHostVisible() { 69 return IsVisible(); 70 } 71 72 void MenuHost::ShowMenuHost(bool do_capture) { 73 // Doing a capture may make us get capture lost. Ignore it while we're in the 74 // process of showing. 75 ignore_capture_lost_ = true; 76 Show(); 77 if (do_capture) 78 native_widget_private()->SetCapture(); 79 ignore_capture_lost_ = false; 80 } 81 82 void MenuHost::HideMenuHost() { 83 ignore_capture_lost_ = true; 84 ReleaseMenuHostCapture(); 85 Hide(); 86 ignore_capture_lost_ = false; 87 } 88 89 void MenuHost::DestroyMenuHost() { 90 HideMenuHost(); 91 destroying_ = true; 92 static_cast<MenuHostRootView*>(GetRootView())->ClearSubmenu(); 93 Close(); 94 } 95 96 void MenuHost::SetMenuHostBounds(const gfx::Rect& bounds) { 97 SetBounds(bounds); 98 } 99 100 void MenuHost::ReleaseMenuHostCapture() { 101 if (native_widget_private()->HasCapture()) 102 native_widget_private()->ReleaseCapture(); 103 } 104 105 //////////////////////////////////////////////////////////////////////////////// 106 // MenuHost, Widget overrides: 107 108 internal::RootView* MenuHost::CreateRootView() { 109 return new MenuHostRootView(this, submenu_); 110 } 111 112 bool MenuHost::ShouldReleaseCaptureOnMouseReleased() const { 113 return false; 114 } 115 116 void MenuHost::OnMouseCaptureLost() { 117 if (destroying_ || ignore_capture_lost_) 118 return; 119 MenuController* menu_controller = 120 submenu_->GetMenuItem()->GetMenuController(); 121 if (menu_controller && !menu_controller->drag_in_progress()) 122 menu_controller->CancelAll(); 123 Widget::OnMouseCaptureLost(); 124 } 125 126 void MenuHost::OnNativeWidgetDestroyed() { 127 if (!destroying_) { 128 // We weren't explicitly told to destroy ourselves, which means the menu was 129 // deleted out from under us (the window we're parented to was closed). Tell 130 // the SubmenuView to drop references to us. 131 submenu_->MenuHostDestroyed(); 132 } 133 Widget::OnNativeWidgetDestroyed(); 134 } 135 136 void MenuHost::OnOwnerClosing() { 137 if (destroying_) 138 return; 139 140 MenuController* menu_controller = 141 submenu_->GetMenuItem()->GetMenuController(); 142 if (menu_controller && !menu_controller->drag_in_progress()) 143 menu_controller->CancelAll(); 144 } 145 146 } // namespace views 147