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