Home | History | Annotate | Download | only in controls
      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