// 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