12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/custom_button.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/test/test_cursor_client.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/layout.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/screen.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/checkbox.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/image_button.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/button/label_button.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/menu_button.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/radio_button.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/link.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/textfield/textfield.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/test/views_test_base.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace views {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestCustomButton : public CustomButton {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit TestCustomButton(ButtonListener* listener)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : CustomButton(listener) {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TestCustomButton() {}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestCustomButton);
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void PerformGesture(CustomButton* button, ui::EventType event_type) {
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::GestureEventDetails gesture_details(event_type);
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TimeDelta time_stamp = base::TimeDelta::FromMicroseconds(0);
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ui::GestureEvent gesture_event(0, 0, 0, time_stamp, gesture_details);
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  button->OnGestureEvent(&gesture_event);
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef ViewsTestBase CustomButtonTest;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Tests that hover state changes correctly when visiblity/enableness changes.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a widget so that the CustomButton can query the hover state
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // correctly.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Widget> widget(new Widget);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.bounds = gfx::Rect(0, 0, 650, 650);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget->Init(params);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget->Show();
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  aura::test::TestCursorClient cursor_client(
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      widget->GetNativeView()->GetRootWindow());
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Position the widget in a way so that it is under the cursor.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Point cursor = gfx::Screen::GetScreenFor(
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      widget->GetNativeView())->GetCursorScreenPoint();
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget_bounds.set_origin(cursor);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget->SetBounds(widget_bounds);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestCustomButton* button = new TestCustomButton(NULL);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget->SetContentsView(button);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Point center(10, 10);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED, center, center,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        ui::EF_LEFT_MOUSE_BUTTON,
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        ui::EF_LEFT_MOUSE_BUTTON));
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_PRESSED, button->state());
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED, center, center,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         ui::EF_LEFT_MOUSE_BUTTON,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         ui::EF_LEFT_MOUSE_BUTTON));
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->SetEnabled(false);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_DISABLED, button->state());
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->SetEnabled(true);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->SetVisible(false);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button->SetVisible(true);
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // In Aura views, no new hover effects are invoked if mouse events
977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // are disabled.
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  cursor_client.DisableMouseEvents();
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  button->SetEnabled(false);
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_DISABLED, button->state());
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  button->SetEnabled(true);
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  button->SetVisible(false);
1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  button->SetVisible(true);
1107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Tests that gesture events correctly change the button state.
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(CustomButtonTest, GestureEventsSetState) {
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Create a widget so that the CustomButton can query the hover state
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // correctly.
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<Widget> widget(new Widget);
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  params.bounds = gfx::Rect(0, 0, 650, 650);
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  widget->Init(params);
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  widget->Show();
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  aura::test::TestCursorClient cursor_client(
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      widget->GetNativeView()->GetRootWindow());
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  TestCustomButton* button = new TestCustomButton(NULL);
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  widget->SetContentsView(button);
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PerformGesture(button, ui::ET_GESTURE_TAP_DOWN);
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_PRESSED, button->state());
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PerformGesture(button, ui::ET_GESTURE_SHOW_PRESS);
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_PRESSED, button->state());
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PerformGesture(button, ui::ET_GESTURE_TAP_CANCEL);
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Ensure subclasses of CustomButton are correctly recognized as CustomButton.
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(CustomButtonTest, AsCustomButton) {
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 text;
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LabelButton label_button(NULL, text);
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(CustomButton::AsCustomButton(&label_button));
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ImageButton image_button(NULL);
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(CustomButton::AsCustomButton(&image_button));
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Checkbox checkbox(text);
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(CustomButton::AsCustomButton(&checkbox));
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RadioButton radio_button(text, 0);
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(CustomButton::AsCustomButton(&radio_button));
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MenuButton menu_button(NULL, text, NULL, false);
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(CustomButton::AsCustomButton(&menu_button));
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Label label;
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(CustomButton::AsCustomButton(&label));
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Link link(text);
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(CustomButton::AsCustomButton(&link));
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Textfield textfield;
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(CustomButton::AsCustomButton(&textfield));
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace views
172