Code Search for Developers
 
 
  

Button.cpp from FreeOrion at Krugle


Show Button.cpp syntax highlighted

/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   of the License, or (at your option) any later version.
   
   This library 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
   Lesser General Public License for more details.
    
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.
    
   Zach Laine
   whatwasthataddress@hotmail.com */

#include <GG/Button.h>

#include <GG/DrawUtil.h>
#include <GG/Layout.h>
#include <GG/StyleFactory.h>
#include <GG/WndEditor.h>
#include <GG/WndEvent.h>

#include <boost/lexical_cast.hpp>


using namespace GG;

namespace {
    struct SetCheckedButtonAction : AttributeChangedAction<int>
    {
        SetCheckedButtonAction(RadioButtonGroup* radio_button_group) : m_radio_button_group(radio_button_group) {}
        void operator()(const int& button)
        {
            int b = button;
            m_radio_button_group->SetCheck(-1);
            m_radio_button_group->SetCheck(b);
        }
        RadioButtonGroup* const m_radio_button_group;
    };
}

////////////////////////////////////////////////
// GG::Button
////////////////////////////////////////////////
Button::Button() :
    TextControl(),
    m_state(BN_UNPRESSED)
{}

Button::Button(int x, int y, int w, int h, const std::string& str, const boost::shared_ptr<Font>& font, Clr color, 
               Clr text_color/* = CLR_BLACK*/, Flags<WndFlag> flags/* = CLICKABLE*/) :
    TextControl(x, y, w, h, str, font, text_color, FORMAT_NONE, flags),
    m_state(BN_UNPRESSED)
{
    m_color = color;
}

Button::ButtonState Button::State() const
{
    return m_state;
}

const SubTexture& Button::UnpressedGraphic() const
{
    return m_unpressed_graphic;
}

const SubTexture& Button::PressedGraphic() const
{
    return m_pressed_graphic;
}

const SubTexture& Button::RolloverGraphic() const
{
    return m_rollover_graphic;
}

void Button::Render()
{
    switch (m_state)
    {
    case BN_PRESSED:
        RenderPressed();
        break;
    case BN_UNPRESSED:
    case BN_ROLLOVER:
        if (m_state == BN_UNPRESSED)
            RenderUnpressed();
        else
            RenderRollover();
        break;
    }
}

void Button::LButtonDown(const Pt& pt, Flags<ModKey> mod_keys)
{
    if (!Disabled()) {
        ButtonState prev_state = m_state;
        m_state = BN_PRESSED;
        if (prev_state == BN_PRESSED && RepeatButtonDown())
            ClickedSignal();
    }
}

void Button::LDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys)
{
    if (!Disabled())
        m_state = BN_PRESSED;
    Wnd::LDrag(pt, move, mod_keys);
}

void Button::LButtonUp(const Pt& pt, Flags<ModKey> mod_keys)
{
    if (!Disabled())
        m_state = BN_UNPRESSED;
}

void Button::LClick(const Pt& pt, Flags<ModKey> mod_keys)
{
    if (!Disabled()) {
        m_state = BN_ROLLOVER;
        ClickedSignal();
    }
}

void Button::MouseHere(const Pt& pt, Flags<ModKey> mod_keys)
{
    if (!Disabled())
        m_state = BN_ROLLOVER;
}

void Button::MouseLeave()
{
    if (!Disabled())
        m_state = BN_UNPRESSED;
}

void Button::SetColor(Clr c)
{
    Control::SetColor(c);
}

void Button::SetState(ButtonState state)
{
    m_state = state;
}

void Button::SetUnpressedGraphic(const SubTexture& st)
{
    m_unpressed_graphic = st;
}

void Button::SetPressedGraphic(const SubTexture& st)
{
    m_pressed_graphic = st;
}

void Button::SetRolloverGraphic(const SubTexture& st)
{
    m_rollover_graphic = st;
}

void Button::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    TextControl::DefineAttributes(editor);
    // TODO: handle setting graphics
}

void Button::RenderPressed()
{
    if (!m_pressed_graphic.Empty()) {
        glColor(Disabled() ? DisabledColor(m_color) : m_color);
        m_pressed_graphic.OrthoBlit(UpperLeft(), LowerRight());
    } else {
        RenderDefault();
    }
    OffsetMove(Pt(1, 1));
    TextControl::Render();
    OffsetMove(Pt(-1, -1));
}

void Button::RenderUnpressed()
{
    if (!m_unpressed_graphic.Empty()) {
        glColor(Disabled() ? DisabledColor(m_color) : m_color);
        m_unpressed_graphic.OrthoBlit(UpperLeft(), LowerRight());
    } else {
        RenderDefault();
    }
    // draw text shadow
    Clr temp = TextColor();  // save original color
    SetTextColor(CLR_SHADOW); // shadow color
    OffsetMove(Pt(2, 2));
    TextControl::Render();
    OffsetMove(Pt(-2, -2));
    SetTextColor(temp);    // restore original color
    // draw text
    TextControl::Render();
}

void Button::RenderRollover()
{
    if (!m_rollover_graphic.Empty()) {
        glColor(Disabled() ? DisabledColor(m_color) : m_color);
        m_rollover_graphic.OrthoBlit(UpperLeft(), LowerRight());
    } else {
        RenderDefault();
    }
    // draw text shadow
    Clr temp = TextColor();  // save original color
    SetTextColor(CLR_SHADOW); // shadow color
    OffsetMove(Pt(2, 2));
    TextControl::Render();
    OffsetMove(Pt(-2, -2));
    SetTextColor(temp);    // restore original color
    // draw text
    TextControl::Render();
}

void Button::RenderDefault()
{
    Pt ul = UpperLeft(), lr = LowerRight();
    BeveledRectangle(ul.x, ul.y, lr.x, lr.y,
                     Disabled() ? DisabledColor(m_color) : m_color,
                     Disabled() ? DisabledColor(m_color) : m_color,
                     (m_state != BN_PRESSED), 1);
}


////////////////////////////////////////////////
// GG::StateButton
////////////////////////////////////////////////
StateButton::StateButton() :
    TextControl(),
    m_checked(false),
    m_style(SBSTYLE_3D_XBOX)
{}

StateButton::StateButton(int x, int y, int w, int h, const std::string& str, const boost::shared_ptr<Font>& font, Flags<TextFormat> format, 
                         Clr color, Clr text_color/* = CLR_BLACK*/, Clr interior/* = CLR_ZERO*/, StateButtonStyle style/* = SBSTYLE_3D_XBOX*/,
                         Flags<WndFlag> flags/* = CLICKABLE*/) :
    TextControl(x, y, w, h, str, font, text_color, format, flags),
    m_checked(false),
    m_int_color(interior),
    m_style(style)
{
    m_color = color;
    SetDefaultButtonPosition();
}

Pt StateButton::MinUsableSize() const
{
    Pt text_lr = m_text_ul + TextControl::MinUsableSize();
    return Pt(std::max(m_button_lr.x, text_lr.x) - std::min(m_button_ul.x, m_text_ul.x),
              std::max(m_button_lr.y, text_lr.y) - std::min(m_button_ul.y, m_text_ul.y));
}

bool StateButton::Checked() const
{
    return m_checked;
}

Clr StateButton::InteriorColor() const
{
    return m_int_color;
}

StateButtonStyle StateButton::Style() const
{
    return m_style;
}

void StateButton::Render()
{
    const int BEVEL = 2;

    // draw button
    Pt cl_ul = ClientUpperLeft();
    Pt cl_lr = ClientLowerRight();
    Pt bn_ul = cl_ul + m_button_ul;
    Pt bn_lr = cl_ul + m_button_lr;

    Pt additional_text_offset;

    switch (m_style) {
    case SBSTYLE_3D_XBOX:
        BeveledRectangle(bn_ul.x, bn_ul.y, bn_lr.x, bn_lr.y,
                         Disabled() ? DisabledColor(m_int_color) : m_int_color,
                         Disabled() ? DisabledColor(m_color) : m_color,
                         false, BEVEL);
        if (m_checked)
            BeveledX(bn_ul.x + 2 * BEVEL, bn_ul.y + 2 * BEVEL, bn_lr.x - 2 * BEVEL, bn_lr.y - 2 * BEVEL,
                     m_disabled ? DisabledColor(m_color) : m_color);
        break;
    case SBSTYLE_3D_CHECKBOX:
        BeveledRectangle(bn_ul.x, bn_ul.y, bn_lr.x, bn_lr.y,
                         Disabled() ? DisabledColor(m_int_color) : m_int_color,
                         Disabled() ? DisabledColor(m_color) : m_color,
                         false, BEVEL);
        if (m_checked)
            BeveledCheck(bn_ul.x + 2 * BEVEL, bn_ul.y + 2 * BEVEL, bn_lr.x - 2 * BEVEL, bn_lr.y - 2 * BEVEL,
                         Disabled() ? DisabledColor(m_color) : m_color);
        break;
    case SBSTYLE_3D_RADIO:
        BeveledCircle(bn_ul.x, bn_ul.y, bn_lr.x, bn_lr.y,
                      Disabled() ? DisabledColor(m_int_color) : m_int_color,
                      Disabled() ? DisabledColor(m_color) : m_color,
                      false, BEVEL);
        if (m_checked)
            Bubble(bn_ul.x + 2 * BEVEL, bn_ul.y + 2 * BEVEL, bn_lr.x - 2 * BEVEL, bn_lr.y - 2 * BEVEL,
                   Disabled() ? DisabledColor(m_color) : m_color);
        break;
    case SBSTYLE_3D_BUTTON:
        BeveledRectangle(bn_ul.x, bn_ul.y, bn_lr.x, bn_lr.y,
                         Disabled() ? DisabledColor(m_color) : m_color,
                         Disabled() ? DisabledColor(m_color) : m_color,
                         !m_checked, BEVEL);
        break;
    case SBSTYLE_3D_ROUND_BUTTON:
        BeveledCircle(bn_ul.x, bn_ul.y, bn_lr.x, bn_lr.y,
                      Disabled() ? DisabledColor(m_color) : m_color,
                      Disabled() ? DisabledColor(m_color) : Color(),
                      !m_checked, BEVEL);
        break;
    case SBSTYLE_3D_TOP_ATTACHED_TAB: {
        Clr color_to_use = m_checked ? m_color : DarkColor(m_color);
        color_to_use = Disabled() ? DisabledColor(color_to_use) : color_to_use;
        if (!m_checked) {
            cl_ul.y += BEVEL;
            additional_text_offset.y = BEVEL / 2;
        }
        BeveledRectangle(cl_ul.x, cl_ul.y, cl_lr.x, cl_lr.y,
                         color_to_use, color_to_use,
                         true, BEVEL,
                         true, true, true, false);
        break;
    }
    case SBSTYLE_3D_TOP_DETACHED_TAB: {
        Clr color_to_use = m_checked ? m_color : DarkColor(m_color);
        color_to_use = Disabled() ? DisabledColor(color_to_use) : color_to_use;
        if (!m_checked) {
            cl_ul.y += BEVEL;
            additional_text_offset.y = BEVEL / 2;
        }
        BeveledRectangle(cl_ul.x, cl_ul.y, cl_lr.x, cl_lr.y,
                         color_to_use, color_to_use,
                         true, BEVEL);
        break;
    }
    }

    OffsetMove(m_text_ul + additional_text_offset);
    TextControl::Render();
    OffsetMove(-(m_text_ul + additional_text_offset));
}

void StateButton::LClick(const Pt& pt, Flags<ModKey> mod_keys)
{
    if (!Disabled())
        SetCheck(!m_checked);
}

void StateButton::SizeMove(const Pt& ul, const Pt& lr)
{
    RepositionButton();
    TextControl::SizeMove(ul, lr);
}

void StateButton::Reset()
{
    SetCheck(false);
}

void StateButton::SetCheck(bool b/* = true*/)
{
    CheckedSignal(m_checked = b);
}

void StateButton::RepositionButton()
{
    if (m_style == SBSTYLE_3D_TOP_ATTACHED_TAB ||
        m_style == SBSTYLE_3D_TOP_DETACHED_TAB) {
        m_button_ul = Pt();
        m_button_lr = Pt();
        m_text_ul = Pt();
    } else {
        int w = Width();
        int h = Height();
        const int BN_W = m_button_lr.x - m_button_ul.x;
        const int BN_H = m_button_lr.y - m_button_ul.y;
        int bn_x = m_button_ul.x;
        int bn_y = m_button_ul.y;
        Flags<TextFormat> format = GetTextFormat();
        const double SPACING = 0.5; // the space to leave between the button and text, as a factor of the button's size (width or height)
        if (format & FORMAT_VCENTER)       // center button vertically
            bn_y = static_cast<int>((h - BN_H) / 2.0 + 0.5);
        if (format & FORMAT_TOP) {         // put button at top, text just below
            bn_y = 0;
            m_text_ul.y = BN_H;
        }
        if (format & FORMAT_BOTTOM) {      // put button at bottom, text just above
            bn_y = (h - BN_H);
            m_text_ul.y = static_cast<int>(h - (BN_H * (1 + SPACING)) - ((GetLineData().size() - 1) * GetFont()->Lineskip() + GetFont()->Height()) + 0.5);
        }

        if (format & FORMAT_CENTER) {      // center button horizontally
            if (format & FORMAT_VCENTER) { // if both the button and the text are to be centered, bad things happen
                format |= FORMAT_LEFT;     // so go to the default (FORMAT_CENTER|FORMAT_LEFT)
                format &= ~FORMAT_CENTER;
            } else {
                bn_x = static_cast<int>((w - bn_x) / 2.0 - BN_W / 2.0 + 0.5);
            }
        }
        if (format & FORMAT_LEFT) {        // put button at left, text just to the right
            bn_x = 0;
            if (format & FORMAT_VCENTER)
                m_text_ul.x = static_cast<int>(BN_W * (1 + SPACING) + 0.5);
        }
        if (format & FORMAT_RIGHT) {       // put button at right, text just to the left
            bn_x = (w - BN_W);
            if (format & FORMAT_VCENTER)
                m_text_ul.x = static_cast<int>(-BN_W * (1 + SPACING) + 0.5);
        }
        SetTextFormat(format);
        m_button_ul = Pt(bn_x, bn_y);
        m_button_lr = m_button_ul + Pt(BN_W, BN_H);
    }
}

void StateButton::SetButtonPosition(const Pt& ul, const Pt& lr)
{
    int bn_x = ul.x;
    int bn_y = ul.y;
    int bn_w = lr.x - ul.x;
    int bn_h = lr.y - ul.y;

    if (bn_w <= 0 || bn_h <= 0)               // if one of these is invalid,
        bn_w = bn_h = GetFont()->PointSize(); // set button width and height to text height

    if (bn_x == -1 || bn_y == -1) {
        m_button_ul = Pt(0, 0);
        m_button_lr = Pt(bn_w, bn_h);
        RepositionButton();
    } else {
        m_button_ul = Pt(bn_x, bn_y);
        m_button_lr = m_button_ul + Pt(bn_w, bn_h);
    }
}

void StateButton::SetDefaultButtonPosition()
{
    SetButtonPosition(Pt(-1, -1), Pt(-1, -1));
}

void StateButton::SetColor(Clr c)
{
    Control::SetColor(c);
}

void StateButton::SetInteriorColor(Clr c)
{
    m_int_color = c;
}

void StateButton::SetStyle(StateButtonStyle bs)
{
    m_style = bs;
}

void StateButton::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    TextControl::DefineAttributes(editor);
    editor->Label("StateButton");
    editor->Attribute("Checked", m_checked);
    editor->Attribute("Interior Color", m_int_color);
    editor->Attribute("Button Style", m_style,
                      SBSTYLE_3D_XBOX, SBSTYLE_3D_ROUND_BUTTON);
    editor->Attribute("Button Upper Left", m_button_ul);
    editor->Attribute("Button Lower Right", m_button_lr);
    editor->Attribute("Text Upper Left", m_text_ul);
}

Pt StateButton::ButtonUpperLeft() const
{
    return m_button_ul;
}

Pt StateButton::ButtonLowerRight() const
{
    return m_button_lr;
}

Pt StateButton::TextUpperLeft() const
{
    return m_text_ul;
}


////////////////////////////////////////////////
// GG::RadioButtonGroup
////////////////////////////////////////////////
// ButtonClickedFunctor
RadioButtonGroup::ButtonClickedFunctor::ButtonClickedFunctor(RadioButtonGroup* group, StateButton* button, int index) :
    m_group(group),
    m_button(button),
    m_index(index),
    m_ignore_clicks(false)
{}

void RadioButtonGroup::ButtonClickedFunctor::operator()(bool checked)
{
    if (!m_ignore_clicks) {
        if (checked) {
            m_group->HandleRadioClick(m_index, false);
        } else {
            m_ignore_clicks = true;
            m_button->SetCheck(true);
            m_ignore_clicks = false;
        }
    }
}

// ButtonSlot
RadioButtonGroup::ButtonSlot::ButtonSlot() :
    button(0)
{}

RadioButtonGroup::ButtonSlot::ButtonSlot(StateButton* button_) :
    button(button_)
{}

// RadioButtonGroup
// static(s)
const int RadioButtonGroup::NO_BUTTON = -1;

RadioButtonGroup::RadioButtonGroup() :
    Control(),
    m_orientation(VERTICAL),
    m_checked_button(NO_BUTTON),
    m_expand_buttons(false),
    m_expand_buttons_proportionally(false),
    m_render_outline(false)
{
    SetColor(CLR_YELLOW);
}

RadioButtonGroup::RadioButtonGroup(int x, int y, int w, int h, Orientation orientation) :
    Control(x, y, w, h),
    m_orientation(orientation),
    m_checked_button(NO_BUTTON),
    m_expand_buttons(false),
    m_expand_buttons_proportionally(false),
    m_render_outline(false)
{
    SetColor(CLR_YELLOW);
}

Pt RadioButtonGroup::MinUsableSize() const
{
    Pt retval;
    for (unsigned int i = 0; i < m_button_slots.size(); ++i) {
        Pt min_usable_size = m_button_slots[i].button->MinUsableSize();
        if (m_orientation == VERTICAL) {
            retval.x = std::max(retval.x, min_usable_size.x);
            retval.y += min_usable_size.y;
        } else {
            retval.x += min_usable_size.x;
            retval.y = std::max(retval.y, min_usable_size.y);
        }
    }
    return retval;
}

Orientation RadioButtonGroup::GetOrientation() const
{
    return m_orientation;
}

int RadioButtonGroup::NumButtons() const
{
    return m_button_slots.size();
}

int RadioButtonGroup::CheckedButton() const
{
    return m_checked_button;
}

bool RadioButtonGroup::ExpandButtons() const
{
    return m_expand_buttons;
}

bool RadioButtonGroup::ExpandButtonsProportionally() const
{
    return m_expand_buttons_proportionally;
}

bool RadioButtonGroup::RenderOutline() const
{
    return m_render_outline;
}

void RadioButtonGroup::RaiseCheckedButton()
{
    if (m_checked_button != NO_BUTTON)
        MoveChildUp(m_button_slots[m_checked_button].button);
}

void RadioButtonGroup::Render()
{
    if (m_render_outline) {
        Pt ul = UpperLeft(), lr = LowerRight();
        Clr color_to_use = Disabled() ? DisabledColor(Color()) : Color();
        FlatRectangle(ul.x, ul.y, lr.x, lr.y, CLR_ZERO, color_to_use, 1);
    }
}

void RadioButtonGroup::SetCheck(int index)
{
    if (index == m_checked_button)
        return;
    if (index < 0 || index >= static_cast<int>(m_button_slots.size()))
        index = NO_BUTTON;
    HandleRadioClick(index, true);
}

void RadioButtonGroup::DisableButton(int index, bool b/* = true*/)
{
    if (0 <= index && index < static_cast<int>(m_button_slots.size())) {
        bool was_disabled = m_button_slots[index].button->Disabled();
        m_button_slots[index].button->Disable(b);
        if (b && !was_disabled && index == m_checked_button)
            SetCheck(NO_BUTTON);
    }
}

void RadioButtonGroup::AddButton(StateButton* bn)
{
    InsertButton(m_button_slots.size(), bn);
}

void RadioButtonGroup::AddButton(const std::string& text, const boost::shared_ptr<Font>& font, Flags<TextFormat> format,
                                 Clr color, Clr text_color/* = CLR_BLACK*/, Clr interior/* = CLR_ZERO*/,
                                 StateButtonStyle style/* = SBSTYLE_3D_RADIO*/)
{
    InsertButton(m_button_slots.size(), text, font, format, color, text_color, interior, style);
}

void RadioButtonGroup::InsertButton(int index, StateButton* bn)
{
    assert(0 <= index && index <= static_cast<int>(m_button_slots.size()));
    if (!m_expand_buttons) {
        Pt min_usable_size = bn->MinUsableSize();
        bn->Resize(Pt(std::max(bn->Width(), min_usable_size.x), std::max(bn->Height(), min_usable_size.y)));
    }
    Pt bn_sz = bn->Size();
    Layout* layout = GetLayout();
    if (!layout) {
        layout = new Layout(0, 0, ClientWidth(), ClientHeight(), 1, 1);
        SetLayout(layout);
    }
    const int CELLS_PER_BUTTON = m_expand_buttons ? 1 : 2;
    const int X_STRETCH = (m_expand_buttons && m_expand_buttons_proportionally) ? bn_sz.x : 1;
    const int Y_STRETCH = (m_expand_buttons && m_expand_buttons_proportionally) ? bn_sz.y : 1;
    if (m_button_slots.empty()) {
        layout->Add(bn, 0, 0);
        if (m_expand_buttons) {
            if (m_orientation == VERTICAL)
                layout->SetRowStretch(0, Y_STRETCH);
            else
                layout->SetColumnStretch(0, X_STRETCH);
        }
    } else {
        if (m_orientation == VERTICAL) {
            layout->ResizeLayout(layout->Rows() + CELLS_PER_BUTTON, 1);
            layout->SetRowStretch(layout->Rows() - CELLS_PER_BUTTON, Y_STRETCH);
        } else {
            layout->ResizeLayout(1, layout->Columns() + CELLS_PER_BUTTON);
            layout->SetColumnStretch(layout->Columns() - CELLS_PER_BUTTON, X_STRETCH);
        }
        for (int i = m_button_slots.size() - 1; index <= i; --i) {
            layout->Remove(m_button_slots[i].button);
            layout->Add(m_button_slots[i].button,
                        m_orientation == VERTICAL ? i * CELLS_PER_BUTTON + CELLS_PER_BUTTON : 0,
                        m_orientation == VERTICAL ? 0 : i * CELLS_PER_BUTTON + CELLS_PER_BUTTON);
            if (m_orientation == VERTICAL)
                layout->SetMinimumRowHeight(i * CELLS_PER_BUTTON + CELLS_PER_BUTTON, layout->MinimumRowHeight(i * CELLS_PER_BUTTON));
            else
                layout->SetMinimumColumnWidth(i * CELLS_PER_BUTTON + CELLS_PER_BUTTON, layout->MinimumColumnWidth(i * CELLS_PER_BUTTON));
        }
        layout->Add(bn, m_orientation == VERTICAL ? index * CELLS_PER_BUTTON : 0, m_orientation == VERTICAL ? 0 : index * CELLS_PER_BUTTON);
    }
    if (m_orientation == VERTICAL)
        layout->SetMinimumRowHeight(index * CELLS_PER_BUTTON, bn_sz.y);
    else
        layout->SetMinimumColumnWidth(index * CELLS_PER_BUTTON, bn_sz.x);
    m_button_slots.insert(m_button_slots.begin() + index, ButtonSlot(bn));

    int old_checked_button = m_checked_button;
    if (index <= m_checked_button)
        ++m_checked_button;
    Reconnect();
    if (m_checked_button != old_checked_button)
        ButtonChangedSignal(m_checked_button);
}

void RadioButtonGroup::InsertButton(int index, const std::string& text, const boost::shared_ptr<Font>& font, Flags<TextFormat> format,
                                    Clr color, Clr text_color/* = CLR_BLACK*/, Clr interior/* = CLR_ZERO*/,
                                    StateButtonStyle style/* = SBSTYLE_3D_RADIO*/)
{
    assert(0 <= index && index <= static_cast<int>(m_button_slots.size()));
    StateButton* button = GetStyleFactory()->NewStateButton(0, 0, 1, 1, text, font, format, color, text_color, interior, style);
    button->Resize(button->MinUsableSize());
    InsertButton(index, button);
}

void RadioButtonGroup::RemoveButton(StateButton* button)
{
    int index = -1;
    for (unsigned int i = 0; i < m_button_slots.size(); ++i) {
        if (m_button_slots[i].button == button) {
            index = i;
            break;
        }
    }
    assert(0 <= index && index < static_cast<int>(m_button_slots.size()));

    const int CELLS_PER_BUTTON = m_expand_buttons ? 1 : 2;
    Layout* layout = GetLayout();
    layout->Remove(m_button_slots[index].button);
    for (unsigned int i = index + 1; i < m_button_slots.size(); ++i) {
        layout->Remove(m_button_slots[i].button);
        if (m_orientation == VERTICAL) {
            layout->Add(m_button_slots[i].button, i * CELLS_PER_BUTTON - CELLS_PER_BUTTON, 0);
            layout->SetRowStretch(i * CELLS_PER_BUTTON - CELLS_PER_BUTTON, layout->RowStretch(i * CELLS_PER_BUTTON));
            layout->SetMinimumRowHeight(i * CELLS_PER_BUTTON - CELLS_PER_BUTTON, layout->MinimumRowHeight(i * CELLS_PER_BUTTON));
        } else {
            layout->Add(m_button_slots[i].button, 0, i * CELLS_PER_BUTTON - CELLS_PER_BUTTON);
            layout->SetColumnStretch(i * CELLS_PER_BUTTON - CELLS_PER_BUTTON, layout->ColumnStretch(i * CELLS_PER_BUTTON));
            layout->SetMinimumColumnWidth(i * CELLS_PER_BUTTON - CELLS_PER_BUTTON, layout->MinimumColumnWidth(i * CELLS_PER_BUTTON));
        }
    }
    m_button_slots[index].connection.disconnect();
    m_button_slots.erase(m_button_slots.begin() + index);
    if (m_button_slots.empty()) {
        layout->ResizeLayout(1, 1);
    } else {
        if (m_orientation == VERTICAL)
            layout->ResizeLayout(layout->Rows() - CELLS_PER_BUTTON, 1);
        else
            layout->ResizeLayout(1, layout->Columns() - CELLS_PER_BUTTON);
    }

    int old_checked_button = m_checked_button;
    if (index == m_checked_button)
        m_checked_button = NO_BUTTON;
    else if (index <= m_checked_button)
        --m_checked_button;
    Reconnect();
    if (m_checked_button != old_checked_button)
        ButtonChangedSignal(m_checked_button);
}

void RadioButtonGroup::ExpandButtons(bool expand)
{
    if (expand != m_expand_buttons) {
        int old_checked_button = m_checked_button;
        std::vector<StateButton*> buttons(m_button_slots.size());
        while (!m_button_slots.empty()) {
            StateButton* button = m_button_slots.back().button;
            buttons[m_button_slots.size() - 1] = button;
            RemoveButton(button);
        }
        m_expand_buttons = expand;
        for (unsigned int i = 0; i < buttons.size(); ++i) {
            AddButton(buttons[i]);
        }
        SetCheck(old_checked_button);
    }
}

void RadioButtonGroup::ExpandButtonsProportionally(bool proportional)
{
    if (proportional != m_expand_buttons_proportionally) {
        int old_checked_button = m_checked_button;
        std::vector<StateButton*> buttons(m_button_slots.size());
        while (!m_button_slots.empty()) {
            StateButton* button = m_button_slots.back().button;
            buttons[m_button_slots.size() - 1] = button;
            RemoveButton(button);
        }
        m_expand_buttons_proportionally = proportional;
        for (unsigned int i = 0; i < buttons.size(); ++i) {
            AddButton(buttons[i]);
        }
        SetCheck(old_checked_button);
    }
}

void RadioButtonGroup::RenderOutline(bool render_outline)
{
    m_render_outline = render_outline;
}

void RadioButtonGroup::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    Control::DefineAttributes(editor);
    editor->Label("RadioButtonGroup");
    boost::shared_ptr<SetCheckedButtonAction> set_checked_button_action(new SetCheckedButtonAction(this));
    editor->Attribute<int>("Checked Button", m_checked_button, set_checked_button_action);
}

const std::vector<RadioButtonGroup::ButtonSlot>& RadioButtonGroup::ButtonSlots() const
{
    return m_button_slots;
}

void RadioButtonGroup::ConnectSignals()
{
    for (unsigned int i = 0; i < m_button_slots.size(); ++i) {
        m_button_slots[i].connection = Connect(m_button_slots[i].button->CheckedSignal, ButtonClickedFunctor(this, m_button_slots[i].button, i));
    }
    SetCheck(m_checked_button);
}

void RadioButtonGroup::HandleRadioClick(int index, bool set_check)
{
    assert(m_checked_button == NO_BUTTON ||
           (0 <= m_checked_button && m_checked_button < static_cast<int>(m_button_slots.size())));
    if (m_checked_button != NO_BUTTON) {
        m_button_slots[m_checked_button].connection.block();
        m_button_slots[m_checked_button].button->SetCheck(false);
        m_button_slots[m_checked_button].connection.unblock();
    }
    if (set_check && index != NO_BUTTON) {
        m_button_slots[index].connection.block();
        m_button_slots[index].button->SetCheck(true);
        m_button_slots[index].connection.unblock();
    }
    ButtonChangedSignal(m_checked_button = index);
}

void RadioButtonGroup::Reconnect()
{
    for (unsigned int i = 0; i < m_button_slots.size(); ++i) {
        m_button_slots[i].connection.disconnect();
    }
    ConnectSignals();
}




See more files for this project here

FreeOrion

FreeOrion brings nation building to a galactic scale with its full-featured grand campaign and in-game racial histories, in addition to the classic 4X model of galactic conquest and tactical combat.

Project homepage: http://sourceforge.net/projects/freeorion
Programming language(s): C,C++
License: other

  Ogre/
    Plugins/
      OISInput.cfg
      OISInput.cpp
      OISInput.h
      OgreGUIInputPlugin.cpp
      OgreGUIInputPlugin.h
      SConscript
    OgreGUI.cpp
    SConscript
  SDL/
    SConscript
    SDLGUI.cpp
  dialogs/
    ColorDlg.cpp
    FileDlg.cpp
    SConscript
    ThreeButtonDlg.cpp
  AlignmentFlags.cpp
  Base.cpp
  BrowseInfoWnd.cpp
  Button.cpp
  Clr.cpp
  Control.cpp
  Cursor.cpp
  DrawUtil.cpp
  DropDownList.cpp
  DynamicGraphic.cpp
  Edit.cpp
  EventPump.cpp
  Font.cpp
  GUI.cpp
  Layout.cpp
  ListBox.cpp
  Menu.cpp
  MultiEdit.cpp
  Plugin.cpp
  PluginInterface.cpp
  PtRect.cpp
  SConscript
  Scroll.cpp
  Slider.cpp
  StaticGraphic.cpp
  StyleFactory.cpp
  TabWnd.cpp
  TextControl.cpp
  Texture.cpp
  Timer.cpp
  Wnd.cpp
  WndEditor.cpp
  WndEvent.cpp
  ZList.cpp
  _vsnprintf.c