1 /*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6 #include "AbstractButton.h"
7
8 #include <View.h>
9
10
11 // #pragma mark - AbstractButton
12
13
AbstractButton(button_policy policy,BMessage * message,BMessenger target)14 AbstractButton::AbstractButton(button_policy policy, BMessage* message,
15 BMessenger target)
16 : View(BRect(0, 0, 0, 0)),
17 BInvoker(message, target),
18 fPolicy(policy),
19 fSelected(false),
20 fPressed(false),
21 fPressedInBounds(false)
22 {
23 }
24
25
26 void
SetPolicy(button_policy policy)27 AbstractButton::SetPolicy(button_policy policy)
28 {
29 fPolicy = policy;
30 }
31
32
33 button_policy
Policy() const34 AbstractButton::Policy() const
35 {
36 return fPolicy;
37 }
38
39
40 void
SetSelected(bool selected)41 AbstractButton::SetSelected(bool selected)
42 {
43 if (selected != fSelected) {
44 fSelected = selected;
45 Invalidate();
46
47 // check whether to notify the listeners depending on the button policy
48 bool notify = false;
49 switch (fPolicy) {
50 case BUTTON_POLICY_TOGGLE_ON_RELEASE:
51 case BUTTON_POLICY_SELECT_ON_RELEASE:
52 // always notify on selection changes
53 notify = true;
54 break;
55 case BUTTON_POLICY_INVOKE_ON_RELEASE:
56 // only notify when the user interaction has been finished
57 notify = !fPressed;
58 break;
59 }
60
61 if (notify) {
62 // notify synchronous listeners
63 _NotifyListeners();
64
65 // send the message
66 if (Message()) {
67 BMessage message(*Message());
68 message.AddBool("selected", IsSelected());
69 InvokeNotify(&message);
70 }
71 }
72 }
73 }
74
75
76 bool
IsSelected() const77 AbstractButton::IsSelected() const
78 {
79 return fSelected;
80 }
81
82
83 void
MouseDown(BPoint where,uint32 buttons,int32 modifiers)84 AbstractButton::MouseDown(BPoint where, uint32 buttons, int32 modifiers)
85 {
86 if (fPressed)
87 return;
88
89 fPressed = true;
90 _PressedUpdate(where);
91 }
92
93
94 void
MouseUp(BPoint where,uint32 buttons,int32 modifiers)95 AbstractButton::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
96 {
97 if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON))
98 return;
99
100 _PressedUpdate(where);
101 fPressed = false;
102 if (fPressedInBounds) {
103 fPressedInBounds = false;
104
105 // update selected state according to policy
106 bool selected = fSelected;
107 switch (fPolicy) {
108 case BUTTON_POLICY_TOGGLE_ON_RELEASE:
109 selected = !fSelected;
110 break;
111 case BUTTON_POLICY_SELECT_ON_RELEASE:
112 selected = true;
113 break;
114 case BUTTON_POLICY_INVOKE_ON_RELEASE:
115 selected = false;
116 break;
117 }
118
119 SetSelected(selected);
120 }
121 Invalidate();
122 }
123
124
125 void
MouseMoved(BPoint where,uint32 buttons,int32 modifiers)126 AbstractButton::MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
127 {
128 if (!fPressed)
129 return;
130
131 _PressedUpdate(where);
132 }
133
134
135 void
AddListener(Listener * listener)136 AbstractButton::AddListener(Listener* listener)
137 {
138 if (listener && !fListeners.HasItem(listener))
139 fListeners.AddItem(listener);
140 }
141
142
143 void
RemoveListener(Listener * listener)144 AbstractButton::RemoveListener(Listener* listener)
145 {
146 if (listener)
147 fListeners.RemoveItem(listener);
148 }
149
150
151 bool
IsPressed() const152 AbstractButton::IsPressed() const
153 {
154 return (fPressed && fPressedInBounds);
155 }
156
157
158 void
_PressedUpdate(BPoint where)159 AbstractButton::_PressedUpdate(BPoint where)
160 {
161 bool pressedInBounds = Bounds().Contains(where);
162 if (pressedInBounds == fPressedInBounds)
163 return;
164
165 fPressedInBounds = pressedInBounds;
166
167 // update the selected state according to the button policy
168 switch (fPolicy) {
169 case BUTTON_POLICY_TOGGLE_ON_RELEASE:
170 case BUTTON_POLICY_SELECT_ON_RELEASE:
171 // nothing to do
172 break;
173 case BUTTON_POLICY_INVOKE_ON_RELEASE:
174 SetSelected(fPressedInBounds);
175 break;
176 }
177
178 Invalidate();
179 }
180
181
182 void
_NotifyListeners()183 AbstractButton::_NotifyListeners()
184 {
185 if (!fListeners.IsEmpty()) {
186 BList listeners(fListeners);
187 for (int32 i = 0; Listener* listener = (Listener*)listeners.ItemAt(i);
188 i++) {
189 listener->SelectionChanged(this);
190 }
191 }
192 }
193
194
195 // #pragma mark - AbstractButton::Listener
196
197
~Listener()198 AbstractButton::Listener::~Listener()
199 {
200 }
201
202