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
16RadioButton::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
23BSize
24RadioButton::MinSize()
25{
26	return BSize(12, 12);
27}
28
29
30BSize
31RadioButton::MaxSize()
32{
33	return MinSize();
34}
35
36
37void
38RadioButton::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
59LabeledRadioButton::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
72void
73LabeledRadioButton::SetTarget(BMessenger messenger)
74{
75	fRadioButton->SetTarget(messenger);
76}
77
78
79void
80LabeledRadioButton::SetSelected(bool selected)
81{
82	fRadioButton->SetSelected(selected);
83}
84
85
86bool
87LabeledRadioButton::IsSelected() const
88{
89	return fRadioButton->IsSelected();
90}
91
92
93// #pragma mark - RadioButtonGroup
94
95
96RadioButtonGroup::RadioButtonGroup(BMessage* message, BMessenger target)
97	: BInvoker(message, target),
98	  fButtons(10),
99	  fSelected(NULL)
100{
101}
102
103
104RadioButtonGroup::~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
112void
113RadioButtonGroup::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
133bool
134RadioButtonGroup::RemoveButton(AbstractButton* button)
135{
136	return RemoveButton(IndexOfButton(button));
137}
138
139
140AbstractButton*
141RadioButtonGroup::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
161int32
162RadioButtonGroup::CountButtons() const
163{
164	return fButtons.CountItems();
165}
166
167
168AbstractButton*
169RadioButtonGroup::ButtonAt(int32 index) const
170{
171	return (AbstractButton*)fButtons.ItemAt(index);
172}
173
174
175int32
176RadioButtonGroup::IndexOfButton(AbstractButton* button) const
177{
178	return fButtons.IndexOf(button);
179}
180
181
182void
183RadioButtonGroup::SelectButton(AbstractButton* button)
184{
185	if (button && fButtons.HasItem(button))
186		button->SetSelected(true);
187}
188
189
190void
191RadioButtonGroup::SelectButton(int32 index)
192{
193	if (AbstractButton* button = ButtonAt(index))
194		button->SetSelected(true);
195}
196
197
198AbstractButton*
199RadioButtonGroup::SelectedButton() const
200{
201	return fSelected;
202}
203
204
205int32
206RadioButtonGroup::SelectedIndex() const
207{
208	return (fSelected ? IndexOfButton(fSelected) : -1);
209}
210
211
212void
213RadioButtonGroup::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
235void
236RadioButtonGroup::_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