blob: 9b0adc722814328a13717c55632d59ce55473bb4 [file] [log] [blame]
// Copyright 2013 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 "ash/shelf/overflow_button.h"
#include <memory>
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_constants.h"
#include "ash/shelf/shelf_view.h"
#include "ash/strings/grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_mask.h"
namespace ash {
OverflowButton::OverflowButton(ShelfView* shelf_view, Shelf* shelf)
: Button(nullptr),
upward_image_(gfx::CreateVectorIcon(kShelfOverflowIcon, kShelfIconColor)),
chevron_image_(nullptr),
shelf_view_(shelf_view),
shelf_(shelf),
background_color_(kShelfDefaultBaseColor) {
DCHECK(shelf_view_);
SetInkDropMode(InkDropMode::ON);
set_ink_drop_base_color(kShelfInkDropBaseColor);
set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity);
set_hide_ink_drop_when_showing_context_menu(false);
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_SHELF_OVERFLOW_NAME));
UpdateChevronImage();
}
OverflowButton::~OverflowButton() = default;
void OverflowButton::OnShelfAlignmentChanged() {
UpdateChevronImage();
}
void OverflowButton::OnOverflowBubbleShown() {
AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
UpdateChevronImage();
}
void OverflowButton::OnOverflowBubbleHidden() {
AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
UpdateChevronImage();
}
void OverflowButton::UpdateShelfItemBackground(SkColor color) {
background_color_ = color;
SchedulePaint();
}
OverflowButton::ChevronDirection OverflowButton::GetChevronDirection() const {
switch (shelf_->alignment()) {
case SHELF_ALIGNMENT_LEFT:
if (shelf_view_->IsShowingOverflowBubble())
return ChevronDirection::LEFT;
return ChevronDirection::RIGHT;
case SHELF_ALIGNMENT_RIGHT:
if (shelf_view_->IsShowingOverflowBubble())
return ChevronDirection::RIGHT;
return ChevronDirection::LEFT;
default:
if (shelf_view_->IsShowingOverflowBubble())
return ChevronDirection::DOWN;
return ChevronDirection::UP;
}
}
void OverflowButton::UpdateChevronImage() {
switch (GetChevronDirection()) {
case ChevronDirection::UP:
chevron_image_ = &upward_image_;
break;
case ChevronDirection::DOWN:
if (downward_image_.isNull()) {
downward_image_ = gfx::ImageSkiaOperations::CreateRotatedImage(
upward_image_, SkBitmapOperations::ROTATION_180_CW);
}
chevron_image_ = &downward_image_;
break;
case ChevronDirection::LEFT:
if (leftward_image_.isNull()) {
leftward_image_ = gfx::ImageSkiaOperations::CreateRotatedImage(
upward_image_, SkBitmapOperations::ROTATION_270_CW);
}
chevron_image_ = &leftward_image_;
break;
case ChevronDirection::RIGHT:
if (rightward_image_.isNull()) {
rightward_image_ = gfx::ImageSkiaOperations::CreateRotatedImage(
upward_image_, SkBitmapOperations::ROTATION_90_CW);
}
chevron_image_ = &rightward_image_;
break;
}
SchedulePaint();
}
std::unique_ptr<views::InkDrop> OverflowButton::CreateInkDrop() {
std::unique_ptr<views::InkDropImpl> ink_drop =
CreateDefaultFloodFillInkDropImpl();
ink_drop->SetShowHighlightOnHover(false);
ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE);
return std::move(ink_drop);
}
std::unique_ptr<views::InkDropRipple> OverflowButton::CreateInkDropRipple()
const {
gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds());
return std::make_unique<views::FloodFillInkDropRipple>(
size(), insets, GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
ink_drop_visible_opacity());
}
bool OverflowButton::ShouldEnterPushedState(const ui::Event& event) {
if (shelf_view_->IsShowingOverflowBubble())
return false;
return Button::ShouldEnterPushedState(event);
}
void OverflowButton::NotifyClick(const ui::Event& event) {
Button::NotifyClick(event);
shelf_view_->ButtonPressed(this, event, GetInkDrop());
}
std::unique_ptr<views::InkDropMask> OverflowButton::CreateInkDropMask() const {
gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds());
return std::make_unique<views::RoundRectInkDropMask>(
size(), insets, kOverflowButtonCornerRadius);
}
void OverflowButton::PaintButtonContents(gfx::Canvas* canvas) {
gfx::Rect bounds = CalculateButtonBounds();
PaintBackground(canvas, bounds);
PaintForeground(canvas, bounds);
}
void OverflowButton::PaintBackground(gfx::Canvas* canvas,
const gfx::Rect& bounds) {
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(background_color_);
canvas->DrawRoundRect(bounds, kOverflowButtonCornerRadius, flags);
}
void OverflowButton::PaintForeground(gfx::Canvas* canvas,
const gfx::Rect& bounds) {
DCHECK(chevron_image_);
canvas->DrawImageInt(
*chevron_image_,
bounds.x() + ((bounds.width() - chevron_image_->width()) / 2),
bounds.y() + ((bounds.height() - chevron_image_->height()) / 2));
}
gfx::Rect OverflowButton::CalculateButtonBounds() const {
ShelfAlignment alignment = shelf_->alignment();
gfx::Rect content_bounds = GetContentsBounds();
// Align the button to the top of a bottom-aligned shelf, to the right edge
// a left-aligned shelf, and to the left edge of a right-aligned shelf.
const int inset = (kShelfSize - kOverflowButtonSize) / 2;
const int x = alignment == SHELF_ALIGNMENT_LEFT
? content_bounds.right() - inset - kOverflowButtonSize
: content_bounds.x() + inset;
return gfx::Rect(x, content_bounds.y() + inset, kOverflowButtonSize,
kOverflowButtonSize);
}
} // namespace ash