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 "RadioButton.h"
7
8 #include <View.h>
9
10 #include "StringView.h"
11
12
13 // #pragma mark - RadioButton
14
15
RadioButton(BMessage * message,BMessenger target)16 RadioButton::RadioButton(BMessage* message, BMessenger target)
17 : AbstractButton(BUTTON_POLICY_SELECT_ON_RELEASE, message, target)
18 {
19 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
20 }
21
22
23 BSize
MinSize()24 RadioButton::MinSize()
25 {
26 return BSize(12, 12);
27 }
28
29
30 BSize
MaxSize()31 RadioButton::MaxSize()
32 {
33 return MinSize();
34 }
35
36
37 void
Draw(BView * container,BRect updateRect)38 RadioButton::Draw(BView* container, BRect updateRect)
39 {
40 BRect rect(Bounds());
41
42 if (IsPressed())
43 container->SetHighColor((rgb_color){ 120, 0, 0, 255 });
44 else
45 container->SetHighColor((rgb_color){ 0, 0, 0, 255 });
46
47 container->StrokeRect(rect);
48
49 if (IsSelected()) {
50 rect.InsetBy(4, 4);
51 container->FillRect(rect);
52 }
53 }
54
55
56 // #pragma mark - LabeledRadioButton
57
58
LabeledRadioButton(const char * label,BMessage * message,BMessenger target)59 LabeledRadioButton::LabeledRadioButton(const char* label, BMessage* message,
60 BMessenger target)
61 : GroupView(B_HORIZONTAL),
62 fRadioButton(new RadioButton(message, target))
63 {
64 SetSpacing(8, 0);
65
66 AddChild(fRadioButton);
67 if (label)
68 AddChild(new StringView(label));
69 }
70
71
72 void
SetTarget(BMessenger messenger)73 LabeledRadioButton::SetTarget(BMessenger messenger)
74 {
75 fRadioButton->SetTarget(messenger);
76 }
77
78
79 void
SetSelected(bool selected)80 LabeledRadioButton::SetSelected(bool selected)
81 {
82 fRadioButton->SetSelected(selected);
83 }
84
85
86 bool
IsSelected() const87 LabeledRadioButton::IsSelected() const
88 {
89 return fRadioButton->IsSelected();
90 }
91
92
93 // #pragma mark - RadioButtonGroup
94
95
RadioButtonGroup(BMessage * message,BMessenger target)96 RadioButtonGroup::RadioButtonGroup(BMessage* message, BMessenger target)
97 : BInvoker(message, target),
98 fButtons(10),
99 fSelected(NULL)
100 {
101 }
102
103
~RadioButtonGroup()104 RadioButtonGroup::~RadioButtonGroup()
105 {
106 // remove as listener from buttons
107 for (int32 i = 0; AbstractButton* button = ButtonAt(i); i++)
108 button->RemoveListener(this);
109 }
110
111
112 void
AddButton(AbstractButton * button)113 RadioButtonGroup::AddButton(AbstractButton* button)
114 {
115 if (!button || fButtons.HasItem(button))
116 return;
117
118 // force radio button policy
119 button->SetPolicy(BUTTON_POLICY_SELECT_ON_RELEASE);
120
121 // deselect the button, if we do already have a selected one
122 if (fSelected)
123 button->SetSelected(false);
124
125 // add ourselves as listener
126 button->AddListener(this);
127
128 // add the button to our list
129 fButtons.AddItem(button);
130 }
131
132
133 bool
RemoveButton(AbstractButton * button)134 RadioButtonGroup::RemoveButton(AbstractButton* button)
135 {
136 return RemoveButton(IndexOfButton(button));
137 }
138
139
140 AbstractButton*
RemoveButton(int32 index)141 RadioButtonGroup::RemoveButton(int32 index)
142 {
143 // remove the button from our list
144 AbstractButton* button = (AbstractButton*)fButtons.RemoveItem(index);
145 if (!button)
146 return NULL;
147
148 // remove ourselves as listener
149 button->RemoveListener(this);
150
151 // if it was the selected one, we don't have a selection anymore
152 if (button == fSelected) {
153 fSelected = NULL;
154 _SelectionChanged();
155 }
156
157 return button;
158 }
159
160
161 int32
CountButtons() const162 RadioButtonGroup::CountButtons() const
163 {
164 return fButtons.CountItems();
165 }
166
167
168 AbstractButton*
ButtonAt(int32 index) const169 RadioButtonGroup::ButtonAt(int32 index) const
170 {
171 return (AbstractButton*)fButtons.ItemAt(index);
172 }
173
174
175 int32
IndexOfButton(AbstractButton * button) const176 RadioButtonGroup::IndexOfButton(AbstractButton* button) const
177 {
178 return fButtons.IndexOf(button);
179 }
180
181
182 void
SelectButton(AbstractButton * button)183 RadioButtonGroup::SelectButton(AbstractButton* button)
184 {
185 if (button && fButtons.HasItem(button))
186 button->SetSelected(true);
187 }
188
189
190 void
SelectButton(int32 index)191 RadioButtonGroup::SelectButton(int32 index)
192 {
193 if (AbstractButton* button = ButtonAt(index))
194 button->SetSelected(true);
195 }
196
197
198 AbstractButton*
SelectedButton() const199 RadioButtonGroup::SelectedButton() const
200 {
201 return fSelected;
202 }
203
204
205 int32
SelectedIndex() const206 RadioButtonGroup::SelectedIndex() const
207 {
208 return (fSelected ? IndexOfButton(fSelected) : -1);
209 }
210
211
212 void
SelectionChanged(AbstractButton * button)213 RadioButtonGroup::SelectionChanged(AbstractButton* button)
214 {
215 // We're only interested in a notification when one of our buttons that
216 // has not been selected one before has become selected.
217 if (!button || !fButtons.HasItem(button) || !button->IsSelected()
218 || button == fSelected) {
219 return;
220 }
221
222 // set the new selection
223 AbstractButton* oldSelected = fSelected;
224 fSelected = button;
225
226 // deselect the old selected button
227 if (oldSelected)
228 oldSelected->SetSelected(false);
229
230 // send out notifications
231 _SelectionChanged();
232 }
233
234
235 void
_SelectionChanged()236 RadioButtonGroup::_SelectionChanged()
237 {
238 // send the message
239 if (Message()) {
240 BMessage message(*Message());
241 message.AddPointer("button group", this);
242 message.AddPointer("selected button", fSelected);
243 message.AddInt32("selected index", SelectedIndex());
244 InvokeNotify(&message);
245 }
246 }
247