root/src/tests/kits/interface/layout/widget_layout_test/RadioButton.cpp
/*
 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "RadioButton.h"

#include <View.h>

#include "StringView.h"


// #pragma mark - RadioButton


RadioButton::RadioButton(BMessage* message, BMessenger target)
        : AbstractButton(BUTTON_POLICY_SELECT_ON_RELEASE, message, target)
{
        SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}


BSize
RadioButton::MinSize()
{
        return BSize(12, 12);
}


BSize
RadioButton::MaxSize()
{
        return MinSize();
}


void
RadioButton::Draw(BView* container, BRect updateRect)
{
        BRect rect(Bounds());

        if (IsPressed())
                container->SetHighColor((rgb_color){ 120, 0, 0, 255 });
        else
                container->SetHighColor((rgb_color){ 0, 0, 0, 255 });

        container->StrokeRect(rect);

        if (IsSelected()) {
                rect.InsetBy(4, 4);
                container->FillRect(rect);
        }
}


// #pragma mark - LabeledRadioButton


LabeledRadioButton::LabeledRadioButton(const char* label, BMessage* message,
        BMessenger target)
        : GroupView(B_HORIZONTAL),
          fRadioButton(new RadioButton(message, target))
{
        SetSpacing(8, 0);

        AddChild(fRadioButton);
        if (label)
                AddChild(new StringView(label));
}


void
LabeledRadioButton::SetTarget(BMessenger messenger)
{
        fRadioButton->SetTarget(messenger);
}


void
LabeledRadioButton::SetSelected(bool selected)
{
        fRadioButton->SetSelected(selected);
}


bool
LabeledRadioButton::IsSelected() const
{
        return fRadioButton->IsSelected();
}


// #pragma mark - RadioButtonGroup


RadioButtonGroup::RadioButtonGroup(BMessage* message, BMessenger target)
        : BInvoker(message, target),
          fButtons(10),
          fSelected(NULL)
{
}


RadioButtonGroup::~RadioButtonGroup()
{
        // remove as listener from buttons
        for (int32 i = 0; AbstractButton* button = ButtonAt(i); i++)
                button->RemoveListener(this);
}


void
RadioButtonGroup::AddButton(AbstractButton* button)
{
        if (!button || fButtons.HasItem(button))
                return;

        // force radio button policy
        button->SetPolicy(BUTTON_POLICY_SELECT_ON_RELEASE);

        // deselect the button, if we do already have a selected one
        if (fSelected)
                button->SetSelected(false);

        // add ourselves as listener
        button->AddListener(this);

        // add the button to our list
        fButtons.AddItem(button);
}


bool
RadioButtonGroup::RemoveButton(AbstractButton* button)
{
        return RemoveButton(IndexOfButton(button));
}


AbstractButton*
RadioButtonGroup::RemoveButton(int32 index)
{
        // remove the button from our list
        AbstractButton* button = (AbstractButton*)fButtons.RemoveItem(index);
        if (!button)
                return NULL;

        // remove ourselves as listener
        button->RemoveListener(this);

        // if it was the selected one, we don't have a selection anymore
        if (button == fSelected) {
                fSelected = NULL;
                _SelectionChanged();
        }

        return button;
}


int32
RadioButtonGroup::CountButtons() const
{
        return fButtons.CountItems();
}


AbstractButton*
RadioButtonGroup::ButtonAt(int32 index) const
{
        return (AbstractButton*)fButtons.ItemAt(index);
}


int32
RadioButtonGroup::IndexOfButton(AbstractButton* button) const
{
        return fButtons.IndexOf(button);
}


void
RadioButtonGroup::SelectButton(AbstractButton* button)
{
        if (button && fButtons.HasItem(button))
                button->SetSelected(true);
}


void
RadioButtonGroup::SelectButton(int32 index)
{
        if (AbstractButton* button = ButtonAt(index))
                button->SetSelected(true);
}


AbstractButton*
RadioButtonGroup::SelectedButton() const
{
        return fSelected;
}


int32
RadioButtonGroup::SelectedIndex() const
{
        return (fSelected ? IndexOfButton(fSelected) : -1);
}


void
RadioButtonGroup::SelectionChanged(AbstractButton* button)
{
        // We're only interested in a notification when one of our buttons that
        // has not been selected one before has become selected.
        if (!button || !fButtons.HasItem(button) || !button->IsSelected()
                || button == fSelected) {
                return;
        }

        // set the new selection
        AbstractButton* oldSelected = fSelected;
        fSelected = button;

        // deselect the old selected button
        if (oldSelected)
                oldSelected->SetSelected(false);

        // send out notifications
        _SelectionChanged();
}


void
RadioButtonGroup::_SelectionChanged()
{
        // send the message
        if (Message()) {
                BMessage message(*Message());
                message.AddPointer("button group", this);
                message.AddPointer("selected button", fSelected);
                message.AddInt32("selected index", SelectedIndex());
                InvokeNotify(&message);
        }
}