15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_scroll_view_container.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPath.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/native_theme/native_theme_aura.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/bubble/bubble_border.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_config.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_controller.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_item_view.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/submenu_view.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/round_rect_painter.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ui::NativeTheme;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kBorderPaddingDueToRoundedCorners = 1;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuScrollButton ------------------------------------------------------------
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuScrollButton is used for the scroll buttons when not all menu items fit
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on screen. MenuScrollButton forwards appropriate events to the
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuController.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuScrollButton : public View {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuScrollButton(SubmenuView* host, bool is_up)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : host_(host),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        is_up_(is_up),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Make our height the same as that of other MenuItemViews.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pref_height_(MenuItemView::pref_menu_height()) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual gfx::Size GetPreferredSize() const OVERRIDE {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Size(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        host_->GetMenuItem()->GetMenuConfig().scroll_arrow_height * 2 - 1,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pref_height_);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool CanDrop(const OSExchangeData& data) OVERRIDE {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(host_->GetMenuItem()->GetMenuController());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Always return true so that drop events are targeted to us.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(host_->GetMenuItem()->GetMenuController());
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->GetMenuItem()->GetMenuController()->OnDragEnteredScrollButton(
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        host_, is_up_);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDragExited() OVERRIDE {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(host_->GetMenuItem()->GetMenuController());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->GetMenuItem()->GetMenuController()->OnDragExitedScrollButton(host_);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const MenuConfig& config = host_->GetMenuItem()->GetMenuConfig();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The background.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect item_bounds(0, 0, width(), height());
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NativeTheme::ExtraParams extra;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra.menu_item.is_selected = false;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetNativeTheme()->Paint(canvas->sk_canvas(),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NativeTheme::kMenuItemBackground,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NativeTheme::kNormal, item_bounds, extra);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Then the arrow.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x = width() / 2;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int y = (height() - config.scroll_arrow_height) / 2;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x_left = x - config.scroll_arrow_height;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x_right = x + config.scroll_arrow_height;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int y_bottom;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!is_up_) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      y_bottom = y;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      y = y_bottom + config.scroll_arrow_height;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      y_bottom = y + config.scroll_arrow_height;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPath path;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path.setFillType(SkPath::kWinding_FillType);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path.lineTo(SkIntToScalar(x_left), SkIntToScalar(y_bottom));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path.lineTo(SkIntToScalar(x_right), SkIntToScalar(y_bottom));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path.lineTo(SkIntToScalar(x), SkIntToScalar(y));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPaint paint;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint.setStyle(SkPaint::kFill_Style);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint.setAntiAlias(true);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint.setColor(config.arrow_color);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawPath(path, paint);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SubmenuView we were created for.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SubmenuView* host_;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Direction of the button.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_up_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Preferred height.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pref_height_;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MenuScrollButton);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuScrollView --------------------------------------------------------------
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuScrollView is a viewport for the SubmenuView. It's reason to exist is so
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that ScrollRectToVisible works.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: It is possible to use ScrollView directly (after making it deal with
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// null scrollbars), but clicking on a child of ScrollView forces the window to
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// become active, which we don't want. As we really only need a fraction of
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// what ScrollView does, so we use a one off variant.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuScrollViewContainer::MenuScrollView : public View {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MenuScrollView(View* child) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(child);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ScrollRectToVisible(const gfx::Rect& rect) OVERRIDE {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: this assumes we only want to scroll in the y direction.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // If the rect is already visible, do not scroll.
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (GetLocalBounds().Contains(rect))
147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return;
148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Scroll just enough so that the rect is visible.
150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    int dy = 0;
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (rect.bottom() > GetLocalBounds().bottom())
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dy = rect.bottom() - GetLocalBounds().bottom();
153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    else
154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dy = rect.y();
155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Convert rect.y() to view's coordinates and make sure we don't show past
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the bottom of the view.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    View* child = GetContents();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    child->SetY(-std::max(0, std::min(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        child->GetPreferredSize().height() - this->height(),
161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        dy - child->y())));
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the contents, which is the SubmenuView.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  View* GetContents() {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return child_at(0);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MenuScrollView);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuScrollViewContainer ----------------------------------------------------
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : content_view_(content_view),
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      arrow_(BubbleBorder::NONE),
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bubble_border_(NULL) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_up_button_ = new MenuScrollButton(content_view, true);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_down_button_ = new MenuScrollButton(content_view, false);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(scroll_up_button_);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(scroll_down_button_);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_view_ = new MenuScrollView(content_view);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(scroll_view_);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  arrow_ = BubbleBorderTypeFromAnchor(
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content_view_->GetMenuItem()->GetMenuController()->GetAnchorPosition());
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (arrow_ != BubbleBorder::NONE)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CreateBubbleBorder();
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CreateDefaultBorder();
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool MenuScrollViewContainer::HasBubbleBorder() {
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return arrow_ != BubbleBorder::NONE;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MenuScrollViewContainer::SetBubbleArrowOffset(int offset) {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(HasBubbleBorder());
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bubble_border_->set_arrow_offset(offset);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuScrollViewContainer::OnPaintBackground(gfx::Canvas* canvas) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (background()) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    View::OnPaintBackground(canvas);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds(0, 0, width(), height());
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NativeTheme::ExtraParams extra;
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const MenuConfig& menu_config = content_view_->GetMenuItem()->GetMenuConfig();
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extra.menu_background.corner_radius = menu_config.corner_radius;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetNativeTheme()->Paint(canvas->sk_canvas(),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NativeTheme::kMenuPopupBackground, NativeTheme::kNormal, bounds, extra);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuScrollViewContainer::Layout() {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Insets insets = GetInsets();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x = insets.left();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int y = insets.top();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width = View::width() - insets.width();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int content_height = height() - insets.height();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!scroll_up_button_->visible()) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scroll_view_->SetBounds(x, y, width, content_height);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scroll_view_->Layout();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size pref = scroll_up_button_->GetPreferredSize();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_up_button_->SetBounds(x, y, width, pref.height());
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content_height -= pref.height();
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int scroll_view_y = y + pref.height();
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref = scroll_down_button_->GetPreferredSize();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_down_button_->SetBounds(x, height() - pref.height() - insets.top(),
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 width, pref.height());
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content_height -= pref.height();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_view_->SetBounds(x, scroll_view_y, width, content_height);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_view_->Layout();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size MenuScrollViewContainer::GetPreferredSize() const {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Insets insets = GetInsets();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prefsize.Enlarge(insets.width(), insets.height());
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return prefsize;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuScrollViewContainer::GetAccessibleState(
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ui::AXViewState* state) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the name from the submenu view.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content_view_->GetAccessibleState(state);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now change the role.
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_MENU_BAR;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some AT (like NVDA) will not process focus events on menu item children
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unless a parent claims to be focused.
262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  state->AddStateFlag(ui::AX_STATE_FOCUSED);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuScrollViewContainer::OnBoundsChanged(
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Rect& previous_bounds) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size content_pref = scroll_view_->GetContents()->GetPreferredSize();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_up_button_->SetVisible(content_pref.height() > height());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_down_button_->SetVisible(content_pref.height() > height());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MenuScrollViewContainer::CreateDefaultBorder() {
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  arrow_ = BubbleBorder::NONE;
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bubble_border_ = NULL;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const MenuConfig& menu_config =
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content_view_->GetMenuItem()->GetMenuConfig();
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool use_border = true;
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int padding = menu_config.corner_radius > 0 ?
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kBorderPaddingDueToRoundedCorners : 0;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(USE_AURA) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (menu_config.native_theme == ui::NativeThemeAura::instance()) {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // In case of NativeThemeAura the border gets drawn with the shadow.
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Furthermore no additional padding is wanted.
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    use_border = false;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    padding = 0;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#endif
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top = menu_config.menu_vertical_border_size + padding;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int left = menu_config.menu_horizontal_border_size + padding;
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom = menu_config.menu_vertical_border_size + padding;
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int right = menu_config.menu_horizontal_border_size + padding;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (use_border) {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetBorder(views::Border::CreateBorderPainter(
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new views::RoundRectPainter(
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            menu_config.native_theme->GetSystemColor(
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                ui::NativeTheme::kColorId_MenuBorderColor),
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            menu_config.corner_radius),
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        gfx::Insets(top, left, bottom, right)));
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetBorder(Border::CreateEmptyBorder(top, left, bottom, right));
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MenuScrollViewContainer::CreateBubbleBorder() {
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bubble_border_ = new BubbleBorder(arrow_,
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    BubbleBorder::SMALL_SHADOW,
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    SK_ColorWHITE);
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetBorder(scoped_ptr<Border>(bubble_border_));
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_background(new BubbleBackground(bubble_border_));
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    MenuAnchorPosition anchor) {
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (anchor) {
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case MENU_ANCHOR_BUBBLE_LEFT:
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return BubbleBorder::RIGHT_CENTER;
3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case MENU_ANCHOR_BUBBLE_RIGHT:
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return BubbleBorder::LEFT_CENTER;
3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case MENU_ANCHOR_BUBBLE_ABOVE:
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return BubbleBorder::BOTTOM_CENTER;
3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case MENU_ANCHOR_BUBBLE_BELOW:
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return BubbleBorder::TOP_CENTER;
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return BubbleBorder::NONE;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
335