blob: c99bf772e4d096d834a4251f04b89a34794984ac [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/vr/elements/button.h"
#include "base/bind.h"
#include "chrome/browser/vr/elements/invisible_hit_target.h"
#include "chrome/browser/vr/elements/rect.h"
#include "chrome/browser/vr/elements/ui_element.h"
#include "chrome/browser/vr/elements/ui_element_name.h"
#include "chrome/browser/vr/elements/vector_icon.h"
#include "chrome/browser/vr/ui_scene_constants.h"
#include "ui/gfx/geometry/point_f.h"
namespace vr {
namespace {
constexpr float kHitPlaneScaleFactorHovered = 1.2f;
constexpr float kDefaultHoverOffsetDMM = 0.048f;
} // namespace
Button::Button(base::RepeatingCallback<void()> click_handler,
AudioDelegate* audio_delegate)
: click_handler_(click_handler), hover_offset_(kDefaultHoverOffsetDMM) {
auto background = std::make_unique<Rect>();
background->SetType(kTypeButtonBackground);
background->set_bubble_events(true);
background->set_contributes_to_parent_bounds(false);
background->SetColor(colors_.background);
background->SetTransitionedProperties(
{TRANSFORM, BACKGROUND_COLOR, FOREGROUND_COLOR});
background_ = background.get();
AddChild(std::move(background));
auto hit_plane = std::make_unique<InvisibleHitTarget>();
hit_plane->SetType(kTypeButtonHitTarget);
hit_plane->set_focusable(false);
hit_plane->set_bubble_events(true);
hit_plane->set_contributes_to_parent_bounds(false);
hit_plane_ = hit_plane.get();
background_->AddChild(std::move(hit_plane));
EventHandlers event_handlers;
event_handlers.hover_enter =
base::BindRepeating(&Button::HandleHoverEnter, base::Unretained(this));
event_handlers.hover_move =
base::BindRepeating(&Button::HandleHoverMove, base::Unretained(this));
event_handlers.hover_leave =
base::BindRepeating(&Button::HandleHoverLeave, base::Unretained(this));
event_handlers.button_down =
base::BindRepeating(&Button::HandleButtonDown, base::Unretained(this));
event_handlers.button_up =
base::BindRepeating(&Button::HandleButtonUp, base::Unretained(this));
set_event_handlers(event_handlers);
Sounds sounds;
sounds.hover_enter = kSoundButtonHover;
sounds.button_down = kSoundButtonClick;
SetSounds(sounds, audio_delegate);
disabled_sounds_.hover_enter = kSoundNone;
disabled_sounds_.button_down = kSoundInactiveButtonClick;
}
Button::~Button() = default;
void Button::Render(UiElementRenderer* renderer,
const CameraModel& model) const {}
void Button::SetButtonColors(const ButtonColors& colors) {
colors_ = colors;
OnStateUpdated();
}
void Button::SetEnabled(bool enabled) {
enabled_ = enabled;
OnStateUpdated();
}
void Button::HandleHoverEnter() {
hovered_ = enabled_;
OnStateUpdated();
}
void Button::HandleHoverMove(const gfx::PointF& position) {
hovered_ = hit_plane_->LocalHitTest(position) && enabled_;
OnStateUpdated();
}
void Button::HandleHoverLeave() {
hovered_ = false;
OnStateUpdated();
}
void Button::HandleButtonDown() {
down_ = enabled_;
OnStateUpdated();
}
void Button::HandleButtonUp() {
down_ = false;
OnStateUpdated();
if (hovered() && click_handler_)
click_handler_.Run();
}
void Button::OnSetColors(const ButtonColors& colors) {}
void Button::OnStateUpdated() {
pressed_ = hovered_ ? down_ : false;
background_->SetColor(colors_.GetBackgroundColor(hovered_, pressed_));
OnSetColors(colors_);
if (hover_offset_ == 0.0f)
return;
if (hovered()) {
background_->SetTranslate(0.0, 0.0, hover_offset_);
hit_plane_->SetScale(kHitPlaneScaleFactorHovered,
kHitPlaneScaleFactorHovered, 1.0f);
} else {
background_->SetTranslate(0.0, 0.0, 0.0);
hit_plane_->SetScale(1.0f, 1.0f, 1.0f);
}
}
void Button::OnSetDrawPhase() {
background_->SetDrawPhase(draw_phase());
hit_plane_->SetDrawPhase(draw_phase());
}
void Button::OnSetName() {
background_->set_owner_name_for_test(name());
hit_plane_->set_owner_name_for_test(name());
}
void Button::OnSetSize(const gfx::SizeF& size) {
if (!background_->contributes_to_parent_bounds()) {
background_->SetSize(size.width(), size.height());
}
hit_plane_->SetSize(size.width(), size.height());
}
void Button::OnSetCornerRadii(const CornerRadii& radii) {
background_->SetCornerRadii(radii);
hit_plane_->SetCornerRadii(radii);
}
void Button::NotifyClientSizeAnimated(const gfx::SizeF& size,
int target_property_id,
cc::KeyframeModel* animation) {
// We could have OnSetSize called in UiElement's Notify handler instead, but
// this may have expensive implications (such as regenerating textures on
// every frame of an animation). For now, keep this elements-specific.
if (target_property_id == BOUNDS) {
OnSetSize(size);
}
UiElement::NotifyClientSizeAnimated(size, target_property_id, animation);
}
const Sounds& Button::GetSounds() const {
if (!enabled()) {
return disabled_sounds_;
}
return UiElement::GetSounds();
}
} // namespace vr