blob: f03f78fd736a83bf9c9fde22dc29cd3ebd9c985c [file] [log] [blame]
// Copyright 2018 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/system/unified/unified_slider_view.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/unified/top_shortcut_button.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/border.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
views::Slider* CreateSlider(UnifiedSliderListener* listener, bool readonly) {
if (readonly)
return new ReadOnlySlider();
return new views::Slider(listener);
}
} // namespace
ReadOnlySlider::ReadOnlySlider() : Slider(nullptr) {}
bool ReadOnlySlider::OnMousePressed(const ui::MouseEvent& event) {
return false;
}
bool ReadOnlySlider::OnMouseDragged(const ui::MouseEvent& event) {
return false;
}
void ReadOnlySlider::OnMouseReleased(const ui::MouseEvent& event) {}
bool ReadOnlySlider::OnKeyPressed(const ui::KeyEvent& event) {
return false;
}
void ReadOnlySlider::OnGestureEvent(ui::GestureEvent* event) {}
UnifiedSliderButton::UnifiedSliderButton(views::ButtonListener* listener,
const gfx::VectorIcon& icon,
int accessible_name_id)
: TopShortcutButton(listener, accessible_name_id) {
SetVectorIcon(icon);
SetBorder(views::CreateEmptyBorder(kUnifiedCircularButtonFocusPadding));
auto path = std::make_unique<SkPath>();
path->addOval(gfx::RectToSkRect(gfx::Rect(CalculatePreferredSize())));
SetProperty(views::kHighlightPathKey, path.release());
}
UnifiedSliderButton::~UnifiedSliderButton() = default;
gfx::Size UnifiedSliderButton::CalculatePreferredSize() const {
return gfx::Size(kTrayItemSize + kUnifiedCircularButtonFocusPadding.width(),
kTrayItemSize + kUnifiedCircularButtonFocusPadding.height());
}
void UnifiedSliderButton::SetVectorIcon(const gfx::VectorIcon& icon) {
SetImage(views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(icon, kUnifiedMenuIconColor));
SetImage(views::Button::STATE_DISABLED,
gfx::CreateVectorIcon(icon, kUnifiedMenuIconColor));
}
void UnifiedSliderButton::SetToggled(bool toggled) {
toggled_ = toggled;
SchedulePaint();
}
void UnifiedSliderButton::PaintButtonContents(gfx::Canvas* canvas) {
gfx::Rect rect(GetContentsBounds());
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(toggled_ ? kUnifiedMenuButtonColorActive
: kUnifiedMenuButtonColor);
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawCircle(gfx::PointF(rect.CenterPoint()), kTrayItemSize / 2, flags);
views::ImageButton::PaintButtonContents(canvas);
}
std::unique_ptr<views::InkDropMask> UnifiedSliderButton::CreateInkDropMask()
const {
gfx::Rect bounds = GetContentsBounds();
return std::make_unique<views::CircleInkDropMask>(
size(), bounds.CenterPoint(), bounds.width() / 2);
}
void UnifiedSliderButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (!GetEnabled())
return;
TopShortcutButton::GetAccessibleNodeData(node_data);
node_data->role = ax::mojom::Role::kToggleButton;
node_data->SetCheckedState(toggled_ ? ax::mojom::CheckedState::kTrue
: ax::mojom::CheckedState::kFalse);
}
UnifiedSliderView::UnifiedSliderView(UnifiedSliderListener* listener,
const gfx::VectorIcon& icon,
int accessible_name_id,
bool readonly)
: button_(new UnifiedSliderButton(listener, icon, accessible_name_id)),
slider_(CreateSlider(listener, readonly)) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kHorizontal, kUnifiedSliderRowPadding,
kUnifiedSliderViewSpacing));
AddChildView(button_);
AddChildView(slider_);
// Prevent an accessibility event while initiallizing this view. Typically
// the first update of the slider value is conducted by the caller function
// to reflect the current value.
slider_->set_enable_accessibility_events(false);
slider_->GetViewAccessibility().OverrideName(
l10n_util::GetStringUTF16(accessible_name_id));
slider_->SetBorder(views::CreateEmptyBorder(kUnifiedSliderPadding));
slider_->SetPreferredSize(gfx::Size(0, kTrayItemSize));
layout->SetFlexForView(slider_, 1);
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
}
void UnifiedSliderView::SetSliderValue(float value, bool by_user) {
// SetValue() calls |listener|, so we should ignore the call when the widget
// is closed, because controllers are already deleted.
// It should allow the case GetWidget() returning null, so that initial
// position can be properly set by controllers before the view is attached to
// a widget.
if (GetWidget() && GetWidget()->IsClosed())
return;
slider_->SetValue(value);
if (by_user)
slider_->set_enable_accessibility_events(true);
}
UnifiedSliderView::~UnifiedSliderView() = default;
} // namespace ash