//------------------------------------------------------------------------------
// emRadioButton.h
//
// Copyright (C) 2005-2010,2014-2016,2021 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emRadioButton_h
#define emRadioButton_h

#ifndef emCheckButton_h
#include <emCore/emCheckButton.h>
#endif

#ifndef emGroup_h
#include <emCore/emGroup.h>
#endif

#ifndef emLinearGroup_h
#include <emCore/emLinearGroup.h>
#endif

#ifndef emRasterGroup_h
#include <emCore/emRasterGroup.h>
#endif


//==============================================================================
//=============================== emRadioButton ================================
//==============================================================================

class emRadioButton : public emCheckButton {

public:

        // Class for a radio button. This is similar to a check button, but in a
        // set of radio buttons, only one button can have checked state, and the
        // user can unchecked a button only by checking another. That is the
        // usual behavior. Actually an emRadioButton does not modify its check
        // state on any click, as long as it is not a member of an
        // emRadioButton::Mechanism, or an emRadioButton::LinearGroup, or an
        // emRadioButton::RasterGroup (it's not a must to use these helper
        // classes).

        emRadioButton(
                ParentArg parent, const emString & name,
                const emString & caption=emString(),
                const emString & description=emString(),
                const emImage & icon=emImage()
        );
                // Like emCheckButton, but if the parent panel is also derived
                // from emRadioButton::Mechanism, this radio button is added
                // automatically to that Mechanism.

        virtual ~emRadioButton();
                // Destructor. Removes the button from any Mechanism.

        class Mechanism : public emUncopyable {

        public:

                // Class for the mechanism of a set of radio buttons.

                Mechanism();
                virtual ~Mechanism();

                void Add(emRadioButton * radioButton);
                        // Add a radio button to this mechanism. If the button
                        // is already a member of another mechanism, it is
                        // removed from that mechanism automatically.

                void AddAll(emPanel * parent);
                        // Add all radio buttons which are children of the given
                        // panel.

                void Remove(emRadioButton * radioButton);
                void RemoveByIndex(int index);
                        // Remove a radio button from this mechanism.

                void RemoveAll();
                        // Remove all radio buttons from this mechanism.

                const emSignal & GetCheckSignal() const;
                        // This signal is signaled whenever there was a change
                        // in the result of GetChecked().

                emRadioButton * GetChecked() const;
                void SetChecked(emRadioButton * radioButton);
                        // Get/set the member button which is currently checked.
                        // NULL means to have no member button checked.

                int GetCheckIndex() const;
                void SetCheckIndex(int index);
                        // Get/set the index of the member button which is
                        // currently checked. -1 means to have no member button
                        // checked.

                int GetCount() const;
                        // Get number of member buttons.

                emRadioButton * GetButton(int index) const;
                        // Get a member button by index.

                int GetIndexOf(const emRadioButton * button) const;
                        // Get the index of a member button, or -1 if not found.

        protected:

                virtual void CheckChanged();
                        // Called whenever there was a change in the result of
                        // GetChecked().

        private:

                emArray<emRadioButton *> Array;
                emSignal CheckSignal;
                int CheckIndex;
        };

        class LinearGroup : public emLinearGroup, public Mechanism {

        public:

                // Combination of emLinearGroup and Mechanism. Any radio buttons
                // created as children of such a group are added automatically
                // to the mechanism (this magic happens in the constructor of
                // emRadioButton).

                LinearGroup(
                        ParentArg parent, const emString & name,
                        const emString & caption=emString(),
                        const emString & description=emString(),
                        const emImage & icon=emImage()
                );
                        // Like the constructor of emLinearGroup.

                virtual ~LinearGroup();
                        // Destructor.
        };

        class RasterGroup : public emRasterGroup, public Mechanism {

        public:

                // Combination of emRasterGroup and Mechanism. Any radio buttons
                // created as children of such a group are added automatically
                // to the mechanism (this magic happens in the constructor of
                // emRadioButton).

                RasterGroup(
                        ParentArg parent, const emString & name,
                        const emString & caption=emString(),
                        const emString & description=emString(),
                        const emImage & icon=emImage()
                );
                        // Like the constructor of emRasterGroup.

                virtual ~RasterGroup();
                        // Destructor.
        };

        class Group : public emGroup, public Mechanism {

        public:

                // ************************************************************
                // *                        WARNING!!!                        *
                // *                                                          *
                // * This class is deprecated and will be removed in a future *
                // * version. Please use LinearGroup or RasterGroup instead.  *
                // ************************************************************
                //
                // Combination of emGroup and Mechanism. Any radio buttons
                // created as children of such a group are added automatically
                // to the mechanism (this magic happens in the constructor of
                // emRadioButton).

                EM_DEPRECATED( // Because the whole class is deprecated!
                        Group(
                                ParentArg parent, const emString & name,
                                const emString & caption=emString(),
                                const emString & description=emString(),
                                const emImage & icon=emImage()
                        )
                );
                        // Like the constructor of emGroup.

                virtual ~Group();
                        // Destructor.
        };

protected:

        virtual void Clicked();

        virtual void CheckChanged();

        virtual emString GetHowTo() const;

private:

        friend class Mechanism;

        Mechanism * Mech;
        int MechIndex;

        static const char * const HowToRadioButton;
};

inline const emSignal & emRadioButton::Mechanism::GetCheckSignal() const
{
        return CheckSignal;
}

inline emRadioButton * emRadioButton::Mechanism::GetChecked() const
{
        return CheckIndex>=0 ? Array[CheckIndex] : NULL;
}

inline int emRadioButton::Mechanism::GetCheckIndex() const
{
        return CheckIndex;
}

inline int emRadioButton::Mechanism::GetCount() const
{
        return Array.GetCount();
}

inline int emRadioButton::Mechanism::GetIndexOf(
        const emRadioButton * button
) const
{
        return button && button->Mech==this ? button->MechIndex : -1;
}


#endif