// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/views/controls/menu/menu_host.h" #include "base/auto_reset.h" #include "base/debug/trace_event.h" #include "ui/events/gestures/gesture_recognizer.h" #include "ui/gfx/path.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/views/controls/menu/menu_host_root_view.h" #include "ui/views/controls/menu/menu_item_view.h" #include "ui/views/controls/menu/menu_scroll_view_container.h" #include "ui/views/controls/menu/submenu_view.h" #include "ui/views/round_rect_painter.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" namespace views { //////////////////////////////////////////////////////////////////////////////// // MenuHost, public: MenuHost::MenuHost(SubmenuView* submenu) : submenu_(submenu), destroying_(false), ignore_capture_lost_(false) { set_auto_release_capture(false); } MenuHost::~MenuHost() { } void MenuHost::InitMenuHost(Widget* parent, const gfx::Rect& bounds, View* contents_view, bool do_capture) { TRACE_EVENT0("views", "MenuHost::InitMenuHost"); Widget::InitParams params(Widget::InitParams::TYPE_MENU); const MenuController* menu_controller = submenu_->GetMenuItem()->GetMenuController(); const MenuConfig& menu_config = submenu_->GetMenuItem()->GetMenuConfig(); bool rounded_border = menu_controller && menu_config.corner_radius > 0; bool bubble_border = submenu_->GetScrollViewContainer() && submenu_->GetScrollViewContainer()->HasBubbleBorder(); params.shadow_type = bubble_border ? Widget::InitParams::SHADOW_TYPE_NONE : Widget::InitParams::SHADOW_TYPE_DROP; params.opacity = (bubble_border || rounded_border) ? Widget::InitParams::TRANSLUCENT_WINDOW : Widget::InitParams::OPAQUE_WINDOW; params.parent = parent ? parent->GetNativeView() : NULL; params.bounds = bounds; Init(params); SetContentsView(contents_view); ShowMenuHost(do_capture); } bool MenuHost::IsMenuHostVisible() { return IsVisible(); } void MenuHost::ShowMenuHost(bool do_capture) { // Doing a capture may make us get capture lost. Ignore it while we're in the // process of showing. base::AutoReset<bool> reseter(&ignore_capture_lost_, true); ShowInactive(); if (do_capture) { // Cancel existing touches, so we don't miss some touch release/cancel // events due to the menu taking capture. ui::GestureRecognizer::Get()->TransferEventsTo(NULL, NULL); native_widget_private()->SetCapture(); } } void MenuHost::HideMenuHost() { ignore_capture_lost_ = true; ReleaseMenuHostCapture(); Hide(); ignore_capture_lost_ = false; } void MenuHost::DestroyMenuHost() { HideMenuHost(); destroying_ = true; static_cast<MenuHostRootView*>(GetRootView())->ClearSubmenu(); Close(); } void MenuHost::SetMenuHostBounds(const gfx::Rect& bounds) { SetBounds(bounds); } void MenuHost::ReleaseMenuHostCapture() { if (native_widget_private()->HasCapture()) native_widget_private()->ReleaseCapture(); } //////////////////////////////////////////////////////////////////////////////// // MenuHost, Widget overrides: internal::RootView* MenuHost::CreateRootView() { return new MenuHostRootView(this, submenu_); } void MenuHost::OnMouseCaptureLost() { if (destroying_ || ignore_capture_lost_) return; MenuController* menu_controller = submenu_->GetMenuItem()->GetMenuController(); if (menu_controller && !menu_controller->drag_in_progress()) menu_controller->CancelAll(); Widget::OnMouseCaptureLost(); } void MenuHost::OnNativeWidgetDestroyed() { if (!destroying_) { // We weren't explicitly told to destroy ourselves, which means the menu was // deleted out from under us (the window we're parented to was closed). Tell // the SubmenuView to drop references to us. submenu_->MenuHostDestroyed(); } Widget::OnNativeWidgetDestroyed(); } void MenuHost::OnOwnerClosing() { if (destroying_) return; MenuController* menu_controller = submenu_->GetMenuItem()->GetMenuController(); if (menu_controller && !menu_controller->drag_in_progress()) menu_controller->CancelAll(); } } // namespace views