| OLD | NEW |
| (Empty) |
| 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/accessibility/ax_view_state.h" | |
| 12 #include "ui/base/cursor/cursor.h" | |
| 13 #include "ui/events/event.h" | |
| 14 #include "ui/events/keycodes/keyboard_codes.h" | |
| 15 #include "ui/gfx/canvas.h" | |
| 16 #include "ui/gfx/color_utils.h" | |
| 17 #include "ui/gfx/font_list.h" | |
| 18 #include "ui/views/controls/link_listener.h" | |
| 19 #include "ui/views/native_cursor.h" | |
| 20 | |
| 21 namespace views { | |
| 22 | |
| 23 const char Link::kViewClassName[] = "Link"; | |
| 24 | |
| 25 Link::Link() : Label(base::string16()) { | |
| 26 Init(); | |
| 27 } | |
| 28 | |
| 29 Link::Link(const base::string16& title) : Label(title) { | |
| 30 Init(); | |
| 31 } | |
| 32 | |
| 33 Link::~Link() { | |
| 34 } | |
| 35 | |
| 36 SkColor Link::GetDefaultEnabledColor() { | |
| 37 #if defined(OS_WIN) | |
| 38 return color_utils::GetSysSkColor(COLOR_HOTLIGHT); | |
| 39 #else | |
| 40 return SkColorSetRGB(0, 51, 153); | |
| 41 #endif | |
| 42 } | |
| 43 | |
| 44 const char* Link::GetClassName() const { | |
| 45 return kViewClassName; | |
| 46 } | |
| 47 | |
| 48 gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) { | |
| 49 if (!enabled()) | |
| 50 return gfx::kNullCursor; | |
| 51 return GetNativeHandCursor(); | |
| 52 } | |
| 53 | |
| 54 bool Link::CanProcessEventsWithinSubtree() const { | |
| 55 // Links need to be able to accept events (e.g., clicking) even though | |
| 56 // in general Labels do not. | |
| 57 return View::CanProcessEventsWithinSubtree(); | |
| 58 } | |
| 59 | |
| 60 bool Link::OnMousePressed(const ui::MouseEvent& event) { | |
| 61 if (!enabled() || | |
| 62 (!event.IsLeftMouseButton() && !event.IsMiddleMouseButton())) | |
| 63 return false; | |
| 64 SetPressed(true); | |
| 65 return true; | |
| 66 } | |
| 67 | |
| 68 bool Link::OnMouseDragged(const ui::MouseEvent& event) { | |
| 69 SetPressed(enabled() && | |
| 70 (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) && | |
| 71 HitTestPoint(event.location())); | |
| 72 return true; | |
| 73 } | |
| 74 | |
| 75 void Link::OnMouseReleased(const ui::MouseEvent& event) { | |
| 76 // Change the highlight first just in case this instance is deleted | |
| 77 // while calling the controller | |
| 78 OnMouseCaptureLost(); | |
| 79 if (enabled() && | |
| 80 (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) && | |
| 81 HitTestPoint(event.location())) { | |
| 82 // Focus the link on click. | |
| 83 RequestFocus(); | |
| 84 | |
| 85 if (listener_) | |
| 86 listener_->LinkClicked(this, event.flags()); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 void Link::OnMouseCaptureLost() { | |
| 91 SetPressed(false); | |
| 92 } | |
| 93 | |
| 94 bool Link::OnKeyPressed(const ui::KeyEvent& event) { | |
| 95 bool activate = ((event.key_code() == ui::VKEY_SPACE) || | |
| 96 (event.key_code() == ui::VKEY_RETURN)); | |
| 97 if (!activate) | |
| 98 return false; | |
| 99 | |
| 100 SetPressed(false); | |
| 101 | |
| 102 // Focus the link on key pressed. | |
| 103 RequestFocus(); | |
| 104 | |
| 105 if (listener_) | |
| 106 listener_->LinkClicked(this, event.flags()); | |
| 107 | |
| 108 return true; | |
| 109 } | |
| 110 | |
| 111 void Link::OnGestureEvent(ui::GestureEvent* event) { | |
| 112 if (!enabled()) | |
| 113 return; | |
| 114 | |
| 115 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | |
| 116 SetPressed(true); | |
| 117 } else if (event->type() == ui::ET_GESTURE_TAP) { | |
| 118 RequestFocus(); | |
| 119 if (listener_) | |
| 120 listener_->LinkClicked(this, event->flags()); | |
| 121 } else { | |
| 122 SetPressed(false); | |
| 123 return; | |
| 124 } | |
| 125 event->SetHandled(); | |
| 126 } | |
| 127 | |
| 128 bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { | |
| 129 // Make sure we don't process space or enter as accelerators. | |
| 130 return (event.key_code() == ui::VKEY_SPACE) || | |
| 131 (event.key_code() == ui::VKEY_RETURN); | |
| 132 } | |
| 133 | |
| 134 void Link::GetAccessibleState(ui::AXViewState* state) { | |
| 135 Label::GetAccessibleState(state); | |
| 136 state->role = ui::AX_ROLE_LINK; | |
| 137 } | |
| 138 | |
| 139 void Link::OnEnabledChanged() { | |
| 140 RecalculateFont(); | |
| 141 View::OnEnabledChanged(); | |
| 142 } | |
| 143 | |
| 144 void Link::OnFocus() { | |
| 145 Label::OnFocus(); | |
| 146 // We render differently focused. | |
| 147 SchedulePaint(); | |
| 148 } | |
| 149 | |
| 150 void Link::OnBlur() { | |
| 151 Label::OnBlur(); | |
| 152 // We render differently focused. | |
| 153 SchedulePaint(); | |
| 154 } | |
| 155 | |
| 156 void Link::SetFontList(const gfx::FontList& font_list) { | |
| 157 Label::SetFontList(font_list); | |
| 158 RecalculateFont(); | |
| 159 } | |
| 160 | |
| 161 void Link::SetText(const base::string16& text) { | |
| 162 Label::SetText(text); | |
| 163 // Disable focusability for empty links. Otherwise Label::GetInsets() will | |
| 164 // give them an unconditional 1-px. inset on every side to allow for a focus | |
| 165 // border, when in this case we probably wanted zero width. | |
| 166 SetFocusable(!text.empty()); | |
| 167 } | |
| 168 | |
| 169 void Link::SetEnabledColor(SkColor color) { | |
| 170 requested_enabled_color_ = color; | |
| 171 if (!pressed_) | |
| 172 Label::SetEnabledColor(requested_enabled_color_); | |
| 173 } | |
| 174 | |
| 175 void Link::SetPressedColor(SkColor color) { | |
| 176 requested_pressed_color_ = color; | |
| 177 if (pressed_) | |
| 178 Label::SetEnabledColor(requested_pressed_color_); | |
| 179 } | |
| 180 | |
| 181 void Link::SetUnderline(bool underline) { | |
| 182 if (underline_ == underline) | |
| 183 return; | |
| 184 underline_ = underline; | |
| 185 RecalculateFont(); | |
| 186 } | |
| 187 | |
| 188 void Link::Init() { | |
| 189 listener_ = NULL; | |
| 190 pressed_ = false; | |
| 191 underline_ = true; | |
| 192 SetEnabledColor(GetDefaultEnabledColor()); | |
| 193 #if defined(OS_WIN) | |
| 194 SetDisabledColor(color_utils::GetSysSkColor(COLOR_WINDOWTEXT)); | |
| 195 SetPressedColor(SkColorSetRGB(200, 0, 0)); | |
| 196 #else | |
| 197 // TODO(beng): source from theme provider. | |
| 198 SetDisabledColor(SK_ColorBLACK); | |
| 199 SetPressedColor(SK_ColorRED); | |
| 200 #endif | |
| 201 RecalculateFont(); | |
| 202 | |
| 203 // Label::Init() calls SetText(), but if that's being called from Label(), our | |
| 204 // SetText() override will not be reached (because the constructed class is | |
| 205 // only a Label at the moment, not yet a Link). So so the set_focusable() | |
| 206 // call explicitly here. | |
| 207 SetFocusable(!text().empty()); | |
| 208 } | |
| 209 | |
| 210 void Link::SetPressed(bool pressed) { | |
| 211 if (pressed_ != pressed) { | |
| 212 pressed_ = pressed; | |
| 213 Label::SetEnabledColor(pressed_ ? | |
| 214 requested_pressed_color_ : requested_enabled_color_); | |
| 215 RecalculateFont(); | |
| 216 SchedulePaint(); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 void Link::RecalculateFont() { | |
| 221 // Underline the link iff it is enabled and |underline_| is true. | |
| 222 const int style = font_list().GetFontStyle(); | |
| 223 const int intended_style = (enabled() && underline_) ? | |
| 224 (style | gfx::Font::UNDERLINE) : (style & ~gfx::Font::UNDERLINE); | |
| 225 if (style != intended_style) | |
| 226 Label::SetFontList(font_list().DeriveWithStyle(intended_style)); | |
| 227 } | |
| 228 | |
| 229 } // namespace views | |
| OLD | NEW |