diff options
Diffstat (limited to 'chrome/views/base_button.cc')
-rw-r--r-- | chrome/views/base_button.cc | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/chrome/views/base_button.cc b/chrome/views/base_button.cc new file mode 100644 index 0000000..6fc440a --- /dev/null +++ b/chrome/views/base_button.cc @@ -0,0 +1,333 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <atlbase.h> +#include <atlapp.h> + +#include "chrome/views/base_button.h" + +#include "base/base_drag_source.h" +#include "chrome/browser/drag_utils.h" +#include "chrome/common/drag_drop_types.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/os_exchange_data.h" + +namespace ChromeViews { + +// How long the hover animation takes if uninterrupted. +static const int kHoverFadeDurationMs = 150; + +//////////////////////////////////////////////////////////////////////////////// +// +// BaseButton - constructors, destructors, initialization +// +//////////////////////////////////////////////////////////////////////////////// + +BaseButton::BaseButton() + : listener_(NULL), + tag_(-1), + state_(BS_NORMAL), + mouse_event_flags_(0), + animate_on_state_change_(true) { + hover_animation_.reset(new ThrobAnimation(this)); + hover_animation_->SetSlideDuration(kHoverFadeDurationMs); +} + +BaseButton::~BaseButton() { +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BaseButton - properties +// +//////////////////////////////////////////////////////////////////////////////// + +bool BaseButton::IsTriggerableEvent(const ChromeViews::MouseEvent& e) { + return e.IsLeftMouseButton(); +} + +void BaseButton::SetState(BaseButton::ButtonState new_state) { + if (new_state != state_) { + if (animate_on_state_change_ || !hover_animation_->IsAnimating()) { + animate_on_state_change_ = true; + if (state_ == BaseButton::BS_NORMAL && new_state == BaseButton::BS_HOT) { + // Button is hovered from a normal state, start hover animation. + hover_animation_->Show(); + } else if (state_ == BaseButton::BS_HOT && + new_state == BaseButton::BS_NORMAL) { + // Button is returning to a normal state from hover, start hover + // fade animation. + hover_animation_->Hide(); + } else { + hover_animation_->Stop(); + } + } + + state_ = new_state; + SchedulePaint(); + } +} + +void BaseButton::SetEnabled(bool f) { + if (f && state_ == BS_DISABLED) { + SetState(BS_NORMAL); + } else if (!f && state_ != BS_DISABLED) { + SetState(BS_DISABLED); + } +} + +void BaseButton::SetAnimationDuration(int duration) { + hover_animation_->SetSlideDuration(duration); +} + +void BaseButton::StartThrobbing(int cycles_til_stop) { + animate_on_state_change_ = false; + hover_animation_->StartThrobbing(cycles_til_stop); +} + +bool BaseButton::IsEnabled() const { + return state_ != BS_DISABLED; +} + +void BaseButton::SetHotTracked(bool f) { + if (f && state_ != BS_DISABLED) { + SetState(BS_HOT); + } else if (!f && state_ != BS_DISABLED) { + SetState(BS_NORMAL); + } +} + +bool BaseButton::IsHotTracked() const { + return state_ == BS_HOT; +} + +bool BaseButton::IsPushed() const { + return state_ == BS_PUSHED; +} + +void BaseButton::SetListener(ButtonListener *l, int tag) { + listener_ = l; + tag_ = tag; +} + +int BaseButton::GetTag() { + return tag_; +} + +bool BaseButton::IsFocusable() const { + return (state_ != BS_DISABLED) && View::IsFocusable(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BaseButton - Tooltips +// +//////////////////////////////////////////////////////////////////////////////// + +bool BaseButton::GetTooltipText(int x, int y, std::wstring* tooltip) { + if (!tooltip_text_.empty()) { + *tooltip = tooltip_text_; + return true; + } + return false; +} + +void BaseButton::SetTooltipText(const std::wstring& tooltip) { + tooltip_text_.assign(tooltip); + TooltipTextChanged(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BaseButton - Events +// +//////////////////////////////////////////////////////////////////////////////// + +bool BaseButton::OnMousePressed(const ChromeViews::MouseEvent& e) { + if (state_ != BS_DISABLED) { + if (IsTriggerableEvent(e) && HitTest(e.GetLocation())) { + SetState(BS_PUSHED); + } + if (IsFocusable()) + RequestFocus(); + } + return true; +} + +bool BaseButton::OnMouseDragged(const ChromeViews::MouseEvent& e) { + if (state_ != BS_DISABLED) { + if (!HitTest(e.GetLocation())) + SetState(BS_NORMAL); + else if (IsTriggerableEvent(e)) + SetState(BS_PUSHED); + else + SetState(BS_HOT); + } + return true; +} + +void BaseButton::OnMouseReleased(const ChromeViews::MouseEvent& e, + bool canceled) { + if (InDrag()) { + // Starting a drag results in a MouseReleased, we need to ignore it. + return; + } + + if (state_ != BS_DISABLED) { + if (canceled || !HitTest(e.GetLocation())) { + SetState(BS_NORMAL); + } else { + SetState(BS_HOT); + if (IsTriggerableEvent(e)) { + NotifyClick(e.GetFlags()); + // We may be deleted at this point (by the listener's notification + // handler) so no more doing anything, just return. + return; + } + } + } +} + +void BaseButton::OnMouseEntered(const ChromeViews::MouseEvent& e) { + using namespace ChromeViews; + if (state_ != BS_DISABLED) { + SetState(BS_HOT); + } +} + +void BaseButton::OnMouseMoved(const ChromeViews::MouseEvent& e) { + using namespace ChromeViews; + + if (state_ != BS_DISABLED) { + if (HitTest(e.GetLocation())) { + SetState(BS_HOT); + } else { + SetState(BS_NORMAL); + } + } +} + +void BaseButton::OnMouseExited(const ChromeViews::MouseEvent& e) { + using namespace ChromeViews; + // Starting a drag results in a MouseExited, we need to ignore it. + if (state_ != BS_DISABLED && !InDrag()) { + SetState(BS_NORMAL); + } +} + +void BaseButton::NotifyClick(int mouse_event_flags) { + mouse_event_flags_ = mouse_event_flags; + if (listener_ != NULL) + listener_->ButtonPressed(this); + // NOTE: don't attempt to reset mouse_event_flags_ as the listener may have + // deleted us. +} + +bool BaseButton::OnKeyPressed(const KeyEvent& e) { + if (state_ != BS_DISABLED) { + if ((e.GetCharacter() == L' ') || (e.GetCharacter() == L'\n')) { + SetState(BS_PUSHED); + return true; + } + } + return false; +} + +bool BaseButton::OnKeyReleased(const KeyEvent& e) { + if (state_ != BS_DISABLED) { + if ((e.GetCharacter() == L' ') || (e.GetCharacter() == L'\n')) { + SetState(BS_NORMAL); + NotifyClick(0); + return true; + } + } + return false; +} + +bool BaseButton::AcceleratorPressed(const Accelerator& accelerator) { + if (enabled_) { + SetState(BS_NORMAL); + NotifyClick(0); + return true; + } + return false; +} + +void BaseButton::AnimationProgressed(const Animation* animation) { + SchedulePaint(); +} + +void BaseButton::OnDragDone() { + SetState(BS_NORMAL); +} + +void BaseButton::ViewHierarchyChanged(bool is_add, View *parent, View *child) { + if (!is_add && state_ != BS_DISABLED) + SetState(BS_NORMAL); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BaseButton - Accessibility +// +//////////////////////////////////////////////////////////////////////////////// + +bool BaseButton::GetAccessibleKeyboardShortcut(std::wstring* shortcut) { + if (!accessible_shortcut_.empty()) { + *shortcut = accessible_shortcut_; + return true; + } + return false; +} + +bool BaseButton::GetAccessibleName(std::wstring* name) { + if (!accessible_name_.empty()) { + *name = accessible_name_; + return true; + } + return false; +} + +void BaseButton::SetAccessibleKeyboardShortcut(const std::wstring& shortcut) { + accessible_shortcut_.assign(shortcut); +} + +void BaseButton::SetAccessibleName(const std::wstring& name) { + accessible_name_.assign(name); +} + +void BaseButton::Paint(ChromeCanvas* canvas) { + View::Paint(canvas); +} + +void BaseButton::Paint(ChromeCanvas* canvas, bool for_drag) { + Paint(canvas); +} + +} // namespace ChromeViews |