1// Copyright (c) 2010 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 "pdf/button.h"
6
7#include "base/logging.h"
8#include "pdf/draw_utils.h"
9#include "ppapi/cpp/input_event.h"
10
11namespace chrome_pdf {
12
13Button::Button()
14    : style_(BUTTON_CLICKABLE), state_(BUTTON_NORMAL), is_pressed_(false) {
15}
16
17Button::~Button() {
18}
19
20bool Button::CreateButton(uint32 id,
21                          const pp::Point& origin,
22                          bool visible,
23                          Control::Owner* owner,
24                          ButtonStyle style,
25                          const pp::ImageData& face_normal,
26                          const pp::ImageData& face_highlighted,
27                          const pp::ImageData& face_pressed) {
28  DCHECK(face_normal.size().GetArea());
29  DCHECK(face_normal.size() == face_highlighted.size());
30  DCHECK(face_normal.size() == face_pressed.size());
31
32  pp::Rect rc(origin, face_normal.size());
33  if (!Control::Create(id, rc, visible, owner))
34    return false;
35
36  style_ = style;
37
38  normal_ = face_normal;
39  highlighted_ = face_highlighted;
40  pressed_ = face_pressed;
41
42  return true;
43}
44
45
46void Button::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
47  if (!visible())
48    return;
49
50  pp::Rect draw_rc = rc.Intersect(rect());
51  if (draw_rc.IsEmpty())
52    return;
53
54  pp::Point origin = draw_rc.point();
55  draw_rc.Offset(-rect().x(), -rect().y());
56
57  AlphaBlend(GetCurrentImage(), draw_rc, image_data, origin, transparency());
58}
59
60bool Button::HandleEvent(const pp::InputEvent& event) {
61  if (!visible())
62    return false;
63
64  // Button handles mouse events only.
65  pp::MouseInputEvent mouse_event(event);
66   if (mouse_event.is_null())
67    return false;
68
69  pp::Point pt = mouse_event.GetPosition();
70  if (!rect().Contains(pt) ||
71      event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
72    ChangeState(BUTTON_NORMAL, false);
73    owner()->SetEventCapture(id(), false);
74    return false;
75  }
76
77  owner()->SetCursor(id(), PP_CURSORTYPE_POINTER);
78  owner()->SetEventCapture(id(), true);
79
80  bool handled = true;
81  switch (event.GetType()) {
82    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
83      if (state_ == BUTTON_NORMAL)
84        ChangeState(BUTTON_HIGHLIGHTED, false);
85      break;
86    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
87      if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
88        ChangeState(BUTTON_PRESSED, false);
89        is_pressed_ = true;
90      }
91      break;
92    case PP_INPUTEVENT_TYPE_MOUSEUP:
93      if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
94          is_pressed_) {
95        OnButtonClicked();
96        is_pressed_ = false;
97      } else {
98        // Since button has not been pressed, return false to allow other
99        // controls (scrollbar) to process mouse button up.
100        return false;
101      }
102      break;
103    default:
104      handled = false;
105      break;
106  }
107
108  return handled;
109}
110
111void Button::OnEventCaptureReleased() {
112  ChangeState(BUTTON_NORMAL, false);
113}
114
115void Button::Show(bool visible, bool invalidate) {
116  // If button become invisible, remove pressed flag.
117  if (!visible)
118    is_pressed_ = false;
119  Control::Show(visible, invalidate);
120}
121
122void Button::AdjustTransparency(uint8 transparency, bool invalidate) {
123  // If button become invisible, remove pressed flag.
124  if (transparency == kTransparentAlpha)
125    is_pressed_ = false;
126  Control::AdjustTransparency(transparency, invalidate);
127}
128
129void Button::SetPressedState(bool pressed) {
130  if (style_ == BUTTON_STATE) {
131    if (IsPressed() != pressed)
132      ChangeState(pressed ? BUTTON_PRESSED_STICKY : BUTTON_NORMAL, true);
133  }
134}
135
136const pp::ImageData& Button::GetCurrentImage() {
137  switch (state_) {
138    case BUTTON_NORMAL: return normal_;
139    case BUTTON_HIGHLIGHTED: return highlighted_;
140    case BUTTON_PRESSED:
141    case BUTTON_PRESSED_STICKY: return pressed_;
142  }
143  NOTREACHED();
144  return normal_;
145}
146
147void Button::ChangeState(ButtonState new_state, bool force) {
148  if (style_ == BUTTON_STATE && !force) {
149    // If button is a state button and pressed state is sticky,
150    // user have to click on this button again to unpress it.
151    if ((state_ == BUTTON_PRESSED_STICKY && new_state != BUTTON_PRESSED_STICKY)
152        ||
153        (state_ != BUTTON_PRESSED_STICKY && new_state == BUTTON_PRESSED_STICKY))
154      return;
155  }
156
157  if (state_ != new_state) {
158    state_ = new_state;
159    owner()->Invalidate(id(), rect());
160  }
161}
162
163void Button::OnButtonClicked() {
164  switch (style_) {
165    case BUTTON_CLICKABLE:
166      ChangeState(BUTTON_HIGHLIGHTED, true);
167      owner()->OnEvent(id(), EVENT_ID_BUTTON_CLICKED, NULL);
168      break;
169    case BUTTON_STATE:
170      SetPressedState(!IsPressed());
171      owner()->OnEvent(id(), EVENT_ID_BUTTON_STATE_CHANGED, NULL);
172      break;
173    default:
174      NOTREACHED();
175  }
176}
177
178}  // namespace chrome_pdf
179
180