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