root/ui/views/controls/link.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetDefaultEnabledColor
  2. GetClassName
  3. GetCursor
  4. HitTestRect
  5. OnMousePressed
  6. OnMouseDragged
  7. OnMouseReleased
  8. OnMouseCaptureLost
  9. OnKeyPressed
  10. OnGestureEvent
  11. SkipDefaultKeyEventProcessing
  12. GetAccessibleState
  13. OnEnabledChanged
  14. OnFocus
  15. OnBlur
  16. SetFontList
  17. SetText
  18. SetEnabledColor
  19. SetPressedColor
  20. SetUnderline
  21. Init
  22. SetPressed
  23. RecalculateFont

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/controls/link.h"

#include "build/build_config.h"

#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/cursor/cursor.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/font_list.h"
#include "ui/views/controls/link_listener.h"

namespace views {

const char Link::kViewClassName[] = "Link";

Link::Link() : Label(base::string16()) {
  Init();
}

Link::Link(const base::string16& title) : Label(title) {
  Init();
}

Link::~Link() {
}

SkColor Link::GetDefaultEnabledColor() {
#if defined(OS_WIN)
  return color_utils::GetSysSkColor(COLOR_HOTLIGHT);
#else
  return SkColorSetRGB(0, 51, 153);
#endif
}

const char* Link::GetClassName() const {
  return kViewClassName;
}

gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
  if (!enabled())
    return gfx::kNullCursor;
  return ui::kCursorHand;
}

bool Link::HitTestRect(const gfx::Rect& rect) const {
  // We need to allow clicks on the link. So we override the implementation in
  // Label and use the default implementation of View.
  return View::HitTestRect(rect);
}

bool Link::OnMousePressed(const ui::MouseEvent& event) {
  if (!enabled() ||
      (!event.IsLeftMouseButton() && !event.IsMiddleMouseButton()))
    return false;
  SetPressed(true);
  return true;
}

bool Link::OnMouseDragged(const ui::MouseEvent& event) {
  SetPressed(enabled() &&
             (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) &&
             HitTestPoint(event.location()));
  return true;
}

void Link::OnMouseReleased(const ui::MouseEvent& event) {
  // Change the highlight first just in case this instance is deleted
  // while calling the controller
  OnMouseCaptureLost();
  if (enabled() &&
      (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) &&
      HitTestPoint(event.location())) {
    // Focus the link on click.
    RequestFocus();

    if (listener_)
      listener_->LinkClicked(this, event.flags());
  }
}

void Link::OnMouseCaptureLost() {
  SetPressed(false);
}

bool Link::OnKeyPressed(const ui::KeyEvent& event) {
  bool activate = ((event.key_code() == ui::VKEY_SPACE) ||
                   (event.key_code() == ui::VKEY_RETURN));
  if (!activate)
    return false;

  SetPressed(false);

  // Focus the link on key pressed.
  RequestFocus();

  if (listener_)
    listener_->LinkClicked(this, event.flags());

  return true;
}

void Link::OnGestureEvent(ui::GestureEvent* event) {
  if (!enabled())
    return;

  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
    SetPressed(true);
  } else if (event->type() == ui::ET_GESTURE_TAP) {
    RequestFocus();
    if (listener_)
      listener_->LinkClicked(this, event->flags());
  } else {
    SetPressed(false);
    return;
  }
  event->SetHandled();
}

bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
  // Make sure we don't process space or enter as accelerators.
  return (event.key_code() == ui::VKEY_SPACE) ||
      (event.key_code() == ui::VKEY_RETURN);
}

void Link::GetAccessibleState(ui::AXViewState* state) {
  Label::GetAccessibleState(state);
  state->role = ui::AX_ROLE_LINK;
}

void Link::OnEnabledChanged() {
  RecalculateFont();
  View::OnEnabledChanged();
}

void Link::OnFocus() {
  Label::OnFocus();
  // We render differently focused.
  SchedulePaint();
}

void Link::OnBlur() {
  Label::OnBlur();
  // We render differently focused.
  SchedulePaint();
}

void Link::SetFontList(const gfx::FontList& font_list) {
  Label::SetFontList(font_list);
  RecalculateFont();
}

void Link::SetText(const base::string16& text) {
  Label::SetText(text);
  // Disable focusability for empty links.  Otherwise Label::GetInsets() will
  // give them an unconditional 1-px. inset on every side to allow for a focus
  // border, when in this case we probably wanted zero width.
  SetFocusable(!text.empty());
}

void Link::SetEnabledColor(SkColor color) {
  requested_enabled_color_ = color;
  if (!pressed_)
    Label::SetEnabledColor(requested_enabled_color_);
}

void Link::SetPressedColor(SkColor color) {
  requested_pressed_color_ = color;
  if (pressed_)
    Label::SetEnabledColor(requested_pressed_color_);
}

void Link::SetUnderline(bool underline) {
  if (underline_ == underline)
    return;
  underline_ = underline;
  RecalculateFont();
}

void Link::Init() {
  listener_ = NULL;
  pressed_ = false;
  underline_ = true;
  SetEnabledColor(GetDefaultEnabledColor());
#if defined(OS_WIN)
  SetDisabledColor(color_utils::GetSysSkColor(COLOR_WINDOWTEXT));
  SetPressedColor(SkColorSetRGB(200, 0, 0));
#else
  // TODO(beng): source from theme provider.
  SetDisabledColor(SK_ColorBLACK);
  SetPressedColor(SK_ColorRED);
#endif
  RecalculateFont();

  // Label::Init() calls SetText(), but if that's being called from Label(), our
  // SetText() override will not be reached (because the constructed class is
  // only a Label at the moment, not yet a Link).  So so the set_focusable()
  // call explicitly here.
  SetFocusable(!text().empty());
}

void Link::SetPressed(bool pressed) {
  if (pressed_ != pressed) {
    pressed_ = pressed;
    Label::SetEnabledColor(pressed_ ?
        requested_pressed_color_ : requested_enabled_color_);
    RecalculateFont();
    SchedulePaint();
  }
}

void Link::RecalculateFont() {
  // Underline the link iff it is enabled and |underline_| is true.
  const int style = font_list().GetFontStyle();
  const int intended_style = (enabled() && underline_) ?
      (style | gfx::Font::UNDERLINE) : (style & ~gfx::Font::UNDERLINE);
  if (style != intended_style)
    Label::SetFontList(font_list().DeriveWithStyle(intended_style));
}

}  // namespace views

/* [<][>][^][v][top][bottom][index][help] */