1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/controls/link.h" 6 7 #include "build/build_config.h" 8 9 #include "base/logging.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "ui/base/accessibility/accessible_view_state.h" 12 #include "ui/base/events/event.h" 13 #include "ui/base/keycodes/keyboard_codes.h" 14 #include "ui/gfx/color_utils.h" 15 #include "ui/gfx/font.h" 16 #include "ui/views/controls/link_listener.h" 17 18 #if defined(USE_AURA) 19 #include "ui/base/cursor/cursor.h" 20 #endif 21 22 namespace views { 23 24 const char Link::kViewClassName[] = "Link"; 25 26 Link::Link() : Label(string16()) { 27 Init(); 28 } 29 30 Link::Link(const string16& title) : Label(title) { 31 Init(); 32 } 33 34 Link::~Link() { 35 } 36 37 SkColor Link::GetDefaultEnabledColor() { 38 #if defined(OS_WIN) 39 return color_utils::GetSysSkColor(COLOR_HOTLIGHT); 40 #else 41 return SkColorSetRGB(0, 51, 153); 42 #endif 43 } 44 45 void Link::OnEnabledChanged() { 46 RecalculateFont(); 47 View::OnEnabledChanged(); 48 } 49 50 const char* Link::GetClassName() const { 51 return kViewClassName; 52 } 53 54 gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) { 55 if (!enabled()) 56 return gfx::kNullCursor; 57 #if defined(USE_AURA) 58 return ui::kCursorHand; 59 #elif defined(OS_WIN) 60 static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND); 61 return g_hand_cursor; 62 #endif 63 } 64 65 bool Link::HitTestRect(const gfx::Rect& rect) const { 66 // We need to allow clicks on the link. So we override the implementation in 67 // Label and use the default implementation of View. 68 return View::HitTestRect(rect); 69 } 70 71 bool Link::OnMousePressed(const ui::MouseEvent& event) { 72 if (!enabled() || 73 (!event.IsLeftMouseButton() && !event.IsMiddleMouseButton())) 74 return false; 75 SetPressed(true); 76 return true; 77 } 78 79 bool Link::OnMouseDragged(const ui::MouseEvent& event) { 80 SetPressed(enabled() && 81 (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) && 82 HitTestPoint(event.location())); 83 return true; 84 } 85 86 void Link::OnMouseReleased(const ui::MouseEvent& event) { 87 // Change the highlight first just in case this instance is deleted 88 // while calling the controller 89 OnMouseCaptureLost(); 90 if (enabled() && 91 (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) && 92 HitTestPoint(event.location())) { 93 // Focus the link on click. 94 RequestFocus(); 95 96 if (listener_) 97 listener_->LinkClicked(this, event.flags()); 98 } 99 } 100 101 void Link::OnMouseCaptureLost() { 102 SetPressed(false); 103 } 104 105 bool Link::OnKeyPressed(const ui::KeyEvent& event) { 106 bool activate = ((event.key_code() == ui::VKEY_SPACE) || 107 (event.key_code() == ui::VKEY_RETURN)); 108 if (!activate) 109 return false; 110 111 SetPressed(false); 112 113 // Focus the link on key pressed. 114 RequestFocus(); 115 116 if (listener_) 117 listener_->LinkClicked(this, event.flags()); 118 119 return true; 120 } 121 122 bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { 123 // Make sure we don't process space or enter as accelerators. 124 return (event.key_code() == ui::VKEY_SPACE) || 125 (event.key_code() == ui::VKEY_RETURN); 126 } 127 128 void Link::GetAccessibleState(ui::AccessibleViewState* state) { 129 Label::GetAccessibleState(state); 130 state->role = ui::AccessibilityTypes::ROLE_LINK; 131 } 132 133 void Link::OnGestureEvent(ui::GestureEvent* event) { 134 if (!enabled()) 135 return; 136 137 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 138 SetPressed(true); 139 } else if (event->type() == ui::ET_GESTURE_TAP) { 140 RequestFocus(); 141 if (listener_) 142 listener_->LinkClicked(this, event->flags()); 143 } else { 144 SetPressed(false); 145 return; 146 } 147 event->SetHandled(); 148 } 149 150 void Link::SetFont(const gfx::Font& font) { 151 Label::SetFont(font); 152 RecalculateFont(); 153 } 154 155 void Link::SetEnabledColor(SkColor color) { 156 requested_enabled_color_ = color; 157 if (!pressed_) 158 Label::SetEnabledColor(requested_enabled_color_); 159 } 160 161 void Link::SetPressedColor(SkColor color) { 162 requested_pressed_color_ = color; 163 if (pressed_) 164 Label::SetEnabledColor(requested_pressed_color_); 165 } 166 167 void Link::SetUnderline(bool underline) { 168 if (underline_ == underline) 169 return; 170 underline_ = underline; 171 RecalculateFont(); 172 } 173 174 void Link::Init() { 175 listener_ = NULL; 176 pressed_ = false; 177 underline_ = true; 178 SetEnabledColor(GetDefaultEnabledColor()); 179 #if defined(OS_WIN) 180 SetDisabledColor(color_utils::GetSysSkColor(COLOR_WINDOWTEXT)); 181 SetPressedColor(SkColorSetRGB(200, 0, 0)); 182 #else 183 // TODO(beng): source from theme provider. 184 SetDisabledColor(SK_ColorBLACK); 185 SetPressedColor(SK_ColorRED); 186 #endif 187 RecalculateFont(); 188 set_focusable(true); 189 } 190 191 void Link::SetPressed(bool pressed) { 192 if (pressed_ != pressed) { 193 pressed_ = pressed; 194 Label::SetEnabledColor(pressed_ ? 195 requested_pressed_color_ : requested_enabled_color_); 196 RecalculateFont(); 197 SchedulePaint(); 198 } 199 } 200 201 void Link::RecalculateFont() { 202 // Underline the link iff it is enabled and |underline_| is true. 203 const int style = font().GetStyle(); 204 const int intended_style = (enabled() && underline_) ? 205 (style | gfx::Font::UNDERLINE) : (style & ~gfx::Font::UNDERLINE); 206 if (style != intended_style) 207 Label::SetFont(font().DeriveFont(0, intended_style)); 208 } 209 210 } // namespace views 211