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