Code Search for Developers
 
 
  

Wnd.cpp from FreeOrion at Krugle


Show Wnd.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/Wnd.h>

#include <GG/GUI.h>
#include <GG/BrowseInfoWnd.h>
#include <GG/DrawUtil.h>
#include <GG/EventPump.h>
#include <GG/Layout.h>
#include <GG/WndEditor.h>
#include <GG/WndEvent.h>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>

using namespace GG;

namespace {
    using namespace boost::multi_index;
    struct GridLayoutWnd
    {
        GridLayoutWnd() : wnd(0) {}
        GridLayoutWnd(Wnd* wnd_, const Pt& ul_, const Pt& lr_) : wnd(wnd_), ul(ul_), lr(lr_) {}
        Wnd* wnd;
        Pt ul;
        Pt lr;
    };
    struct IsLeft
    {
        bool operator()(const Pt& lhs, const Pt& rhs) const {return lhs.x < rhs.x;}
        bool operator()(int x, const Pt& pt) const          {return x < pt.x;}
        bool operator()(const Pt& pt, int x) const          {return pt.x < x;}
    };
    struct IsTop
    {
        bool operator()(const Pt& lhs, const Pt& rhs) const {return lhs.y < rhs.y;}
        bool operator()(int y, const Pt& pt) const          {return y < pt.y;}
        bool operator()(const Pt& pt, int y) const          {return pt.y < y;}
    };
    struct IsRight
    {
        bool operator()(const Pt& lhs, const Pt& rhs) const {return rhs.x < lhs.x;}
        bool operator()(int x, const Pt& pt) const          {return pt.x < x;}
        bool operator()(const Pt& pt, int x) const          {return x < pt.x;}
    };
    struct IsBottom
    {
        bool operator()(const Pt& lhs, const Pt& rhs) const {return rhs.y < lhs.y;}
        bool operator()(int y, const Pt& pt) const          {return pt.y < y;}
        bool operator()(const Pt& pt, int y) const          {return y < pt.y;}
    };
    struct Pointer {};
    struct Left {};
    struct Top {};
    struct Right {};
    struct Bottom {};
    typedef multi_index_container<
        GridLayoutWnd,
        indexed_by<
            ordered_unique<tag<Pointer>, member<GridLayoutWnd, Wnd*, &GridLayoutWnd::wnd> >,
            ordered_non_unique<tag<Left>, member<GridLayoutWnd, Pt, &GridLayoutWnd::ul>, IsLeft>,
            ordered_non_unique<tag<Top>, member<GridLayoutWnd, Pt, &GridLayoutWnd::ul>, IsTop>,
            ordered_non_unique<tag<Right>, member<GridLayoutWnd, Pt, &GridLayoutWnd::lr>, IsRight>,
            ordered_non_unique<tag<Bottom>, member<GridLayoutWnd, Pt, &GridLayoutWnd::lr>, IsBottom>
        >
    > GridLayoutWndContainer;
    typedef GridLayoutWndContainer::index<Pointer>::type::iterator PointerIter;
    typedef GridLayoutWndContainer::index<Left>::type::iterator    LeftIter;
    typedef GridLayoutWndContainer::index<Top>::type::iterator     TopIter;
    typedef GridLayoutWndContainer::index<Right>::type::iterator   RightIter;
    typedef GridLayoutWndContainer::index<Bottom>::type::iterator  BottomIter;

    struct WndHorizontalLess
    {
        bool operator()(const Wnd* lhs, const Wnd* rhs) const {return lhs->UpperLeft().x < rhs->UpperLeft().x;}
    };

    struct WndVerticalLess
    {
        bool operator()(const Wnd* lhs, const Wnd* rhs) const {return lhs->UpperLeft().y < rhs->UpperLeft().y;}
    };

    const int DEFAULT_LAYOUT_BORDER_MARGIN = 0;
    const int DEFAULT_LAYOUT_CELL_MARGIN = 5;

    struct WndSizeFunctor
    {
        std::string operator()(const Wnd* wnd)
        {
            if (!wnd)
                return "";
            std::stringstream stream;
            stream << "(" << wnd->Width() << ", " << wnd->Height() << ")";
            return stream.str();
        }
    };

    struct WndClientSizeFunctor
    {
        std::string operator()(const Wnd* wnd)
        {
            if (!wnd)
                return "";
            std::stringstream stream;
            stream << "(" << wnd->ClientWidth() << ", " << wnd->ClientHeight() << ")";
            return stream.str();
        }
    };

    struct SetWindowTextAction : AttributeChangedAction<std::string>
    {
        SetWindowTextAction(Wnd* wnd) : m_wnd(wnd) {}
        virtual void operator()(const std::string& value)
        {
            if (TextControl* text_control = dynamic_cast<TextControl*>(m_wnd))
                text_control->SetText(value);
        }
    private:
        Wnd* m_wnd;
    };
}

///////////////////////////////////////
// WndFlags
///////////////////////////////////////
const WndFlag GG::CLICKABLE          (1 << 0);
const WndFlag GG::REPEAT_BUTTON_DOWN (1 << 1);
const WndFlag GG::DRAGABLE           (1 << 2);
const WndFlag GG::RESIZABLE          (1 << 3);
const WndFlag GG::ONTOP              (1 << 4);
const WndFlag GG::MODAL              (1 << 5);

GG_FLAGSPEC_IMPL(WndFlag);

namespace {
    bool RegisterWndFlags()
    {
        FlagSpec<WndFlag>& spec = FlagSpec<WndFlag>::instance();
        spec.insert(CLICKABLE, "CLICKABLE", true);
        spec.insert(REPEAT_BUTTON_DOWN, "REPEAT_BUTTON_DOWN", true);
        spec.insert(DRAGABLE, "DRAGABLE", true);
        spec.insert(RESIZABLE, "RESIZABLE", true);
        spec.insert(ONTOP, "ONTOP", true);
        spec.insert(MODAL, "MODAL", true);
        return true;
    }
    bool dummy = RegisterWndFlags();
}


///////////////////////////////////////
// class GG::Wnd
///////////////////////////////////////
// static(s)
int Wnd::s_default_browse_time = 1500;
boost::shared_ptr<BrowseInfoWnd> Wnd::s_default_browse_info_wnd;

Wnd::Wnd() :
    m_done(false),
    m_parent(0),
    m_zorder(0),
    m_visible(true),
    m_clip_children(false),
    m_max_size(1 << 30, 1 << 30),
    m_layout(0),
    m_containing_layout(0),
    m_flags()
{
    m_browse_modes.resize(1);
    m_browse_modes[0].time = s_default_browse_time;
    m_browse_modes[0].wnd = s_default_browse_info_wnd;
}

Wnd::Wnd(int x, int y, int w, int h, Flags<WndFlag> flags/* = CLICKABLE | DRAGABLE*/) :
    m_done(false),
    m_parent(0),
    m_zorder(0),
    m_visible(true),
    m_clip_children(false),
    m_upperleft(x, y),
    m_lowerright(x + w, y + h),
    m_max_size(1 << 30, 1 << 30),
    m_layout(0),
    m_containing_layout(0),
    m_flags(flags)
{
    ValidateFlags();
    m_browse_modes.resize(1);
    m_browse_modes[0].time = s_default_browse_time;
    m_browse_modes[0].wnd = s_default_browse_info_wnd;
}

Wnd::~Wnd()
{
    // remove this-references from Wnds that this Wnd filters
    for (std::set<Wnd*>::iterator it1 = m_filtering.begin(); it1 != m_filtering.end(); ++it1) {
        std::vector<Wnd*>::iterator it2 = std::find((*it1)->m_filters.begin(), (*it1)->m_filters.end(), this);
        if (it2 != (*it1)->m_filters.end())
            (*it1)->m_filters.erase(it2);
    }

    // remove this-references from Wnds that filter this Wnd
    for (std::vector<Wnd*>::iterator it1 = m_filters.begin(); it1 != m_filters.end(); ++it1) {
        (*it1)->m_filtering.erase(this);
    }

    if (Wnd* parent = Parent())
        parent->DetachChild(this);

    GUI::GetGUI()->WndDying(this);

    DeleteChildren();
}

bool Wnd::Clickable() const
{
    return m_flags & CLICKABLE;
}

bool Wnd::RepeatButtonDown() const
{
    return m_flags & REPEAT_BUTTON_DOWN;
}

bool Wnd::Dragable() const
{
    return m_flags & DRAGABLE;
}

bool Wnd::Resizable() const
{
    return m_flags & RESIZABLE;
}

bool Wnd::OnTop() const
{
    return m_flags & ONTOP;
}

bool Wnd::Modal() const
{
    return m_flags & MODAL;
}

bool Wnd::ClipChildren() const
{
    return m_clip_children;
}

bool Wnd::Visible() const
{
    return m_visible;
}

const std::string& Wnd::WindowText() const
{
    return m_text;
}

const std::string& Wnd::DragDropDataType() const
{
    return m_drag_drop_data_type;
}

Pt Wnd::UpperLeft() const
{
    Pt retval = m_upperleft;
    if (m_parent)
        retval += m_parent->ClientUpperLeft();
    return retval;
}

Pt Wnd::LowerRight() const
{
    Pt retval = m_lowerright;
    if (m_parent)
        retval += m_parent->ClientUpperLeft();
    return retval;
}

Pt Wnd::RelativeUpperLeft() const
{
    return m_upperleft;
}

Pt Wnd::RelativeLowerRight() const
{
    return m_lowerright;
}

int Wnd::Width() const
{
    return m_lowerright.x - m_upperleft.x;
}

int Wnd::Height() const
{
    return m_lowerright.y - m_upperleft.y;
}

int Wnd::ZOrder() const
{
    return m_zorder;
}

Pt Wnd::Size() const
{
    return Pt(m_lowerright.x - m_upperleft.x, m_lowerright.y - m_upperleft.y);
}

Pt Wnd::MinSize() const
{
    return m_min_size;
}

Pt Wnd::MaxSize() const
{
    return m_max_size;
}

Pt Wnd::MinUsableSize() const
{
    return Size();
}

Pt Wnd::ClientUpperLeft() const
{
    return UpperLeft();
}

Pt Wnd::ClientLowerRight() const
{
    return LowerRight();
}

Pt Wnd::ClientSize() const
{
    return ClientLowerRight() - ClientUpperLeft();
}

int Wnd::ClientWidth() const
{
    return ClientLowerRight().x - ClientUpperLeft().x;
}

int Wnd::ClientHeight() const
{
    return ClientLowerRight().y - ClientUpperLeft().y;
}

Pt Wnd::ScreenToWindow(const Pt& pt) const
{
    return pt - UpperLeft();
}

Pt Wnd::ScreenToClient(const Pt& pt) const
{
    return pt - ClientUpperLeft();
}

bool Wnd::InWindow(const Pt& pt) const
{
    return pt >= UpperLeft() && pt < LowerRight();
}

bool Wnd::InClient(const Pt& pt) const
{
    return pt >= ClientUpperLeft() && pt < ClientLowerRight();
}

const std::list<Wnd*>& Wnd::Children() const
{
    return m_children;
}

Wnd* Wnd::Parent() const
{
    return m_parent;
}

Wnd* Wnd::RootParent() const
{
    Wnd* retval = m_parent;
    while (retval && retval->Parent()) {
        retval = retval->Parent();
    }
    return retval;
}

Layout* Wnd::GetLayout() const
{
    return m_layout;
}

Layout* Wnd::ContainingLayout() const
{
    return m_containing_layout;
}

const std::vector<Wnd::BrowseInfoMode>& Wnd::BrowseModes() const
{
    return m_browse_modes;
}

const std::string& Wnd::BrowseInfoText(int mode) const
{
    return m_browse_modes.at(mode).text;
}

const boost::shared_ptr<StyleFactory>& Wnd::GetStyleFactory() const
{
    return m_style_factory ? m_style_factory : GUI::GetGUI()->GetStyleFactory();
}

WndRegion Wnd::WindowRegion(const Pt& pt) const
{
    enum {LEFT = 0, MIDDLE = 1, RIGHT = 2};
    enum {TOP = 0, BOTTOM = 2};

    // window regions look like this:
    // 0111112
    // 3444445   // 4 is client area, 0,2,6,8 are corners
    // 3444445
    // 6777778

    int x_pos = MIDDLE;   // default & typical case is that the mouse is over the (non-border) client area
    int y_pos = MIDDLE;

    if (pt.x < ClientUpperLeft().x)
        x_pos = LEFT;
    else if (pt.x > ClientLowerRight().x)
        x_pos = RIGHT;

    if (pt.y < ClientUpperLeft().y)
        y_pos = TOP;
    else if (pt.y > ClientLowerRight().y)
        y_pos = BOTTOM;

    return (Resizable() ? WndRegion(x_pos + 3 * y_pos) : WR_NONE);
}

void Wnd::SetDragDropDataType(const std::string& data_type)
{
    m_drag_drop_data_type = data_type;
}

void Wnd::StartingChildDragDrop(const Wnd* wnd, const Pt& offset)
{}

void Wnd::AcceptDrops(std::list<Wnd*>& wnds, const Pt& pt)
{
    wnds.clear();
}

void Wnd::ChildrenDraggedAway(const std::list<Wnd*>& wnds, const Wnd* destination)
{
    for (std::list<Wnd*>::const_iterator it = wnds.begin(); it != wnds.end(); ++it) {
        DetachChild(*it);
    }
}

void Wnd::SetText(const std::string& str)
{
    m_text = str;
}

void Wnd::Hide(bool children/* = true*/)
{
    m_visible = false;
    if (children) {
        std::list<Wnd*>::iterator it = m_children.begin();
        for (; it != m_children.end(); ++it)
            (*it)->Hide(children);
    }
}

void Wnd::Show(bool children/* = true*/)
{
    m_visible = true;
    if (children) {
        std::list<Wnd*>::iterator it = m_children.begin();
        for (; it != m_children.end(); ++it)
            (*it)->Show(children);
    }
}

void Wnd::ModalInit()
{
}

void Wnd::EnableChildClipping(bool enable/* = true*/)
{
    m_clip_children = enable;
}

void Wnd::BeginClipping()
{
    BeginScissorClipping(ClientUpperLeft(), ClientLowerRight());
}

void Wnd::EndClipping()
{
    EndScissorClipping();
}

void Wnd::MoveTo(const Pt& pt)
{
    SizeMove(pt, pt + Size());
}

void Wnd::OffsetMove(const Pt& pt)
{
    SizeMove(m_upperleft + pt, m_lowerright + pt);
}

void Wnd::SizeMove(const Pt& ul_, const Pt& lr_)
{
    Pt ul = ul_, lr = lr_;
    Pt original_sz = Size();
    bool resized = (original_sz.x != (lr.x - ul.x)) || (original_sz.y != (lr.y - ul.y));
    if (resized) {
        Pt min_sz = MinSize();
        Pt max_sz = MaxSize();
        if (m_layout) {
            Pt layout_min_sz = m_layout->MinSize() + (Size() - ClientSize());
            min_sz.x = std::max(min_sz.x, layout_min_sz.x);
            min_sz.y = std::max(min_sz.y, layout_min_sz.y);
        }
        if (lr.x - ul.x < min_sz.x) {
            if (ul.x != m_upperleft.x)
                ul.x = lr.x - min_sz.x;
            else if (lr.x != m_lowerright.x)
                lr.x = ul.x + min_sz.x;
        } else if (max_sz.x < lr.x - ul.x) {
            if (lr.x != m_lowerright.x)
                lr.x = ul.x + max_sz.x;
            else
                ul.x = lr.x - max_sz.x;
        }
        if (lr.y - ul.y < min_sz.y) {
            if (ul.y != m_upperleft.y)
                ul.y = lr.y - min_sz.y;
            else if (lr.y != m_lowerright.y)
                lr.y = ul.y + min_sz.y;
        } else if (max_sz.y < lr.y - ul.y) {
            if (lr.y != m_lowerright.y)
                lr.y = ul.y + max_sz.y;
            else
                ul.y = lr.y - max_sz.y;
        }
    }
    m_upperleft = ul;
    m_lowerright = lr;
    if (resized) {
        bool size_changed = Size() != original_sz;
        if (m_layout && size_changed)
            m_layout->Resize(ClientSize());
        if (m_containing_layout && size_changed && !dynamic_cast<Layout*>(this))
            m_containing_layout->ChildSizeOrMinSizeOrMaxSizeChanged();
    }
}

void Wnd::Resize(const Pt& sz)
{
    SizeMove(m_upperleft, m_upperleft + sz);
}

void Wnd::SetMinSize(const Pt& sz)
{
    bool min_size_changed = m_min_size != sz;
    m_min_size = sz;
    if (Width() < m_min_size.x || Height() < m_min_size.y)
        Resize(Pt(std::max(Width(), m_min_size.x), std::max(Height(), m_min_size.y)));
    else if (m_containing_layout && min_size_changed && !dynamic_cast<Layout*>(this))
        m_containing_layout->ChildSizeOrMinSizeOrMaxSizeChanged();
}

void Wnd::SetMaxSize(const Pt& sz)
{
    m_max_size = sz;
    if (m_max_size.x < Width() || m_max_size.y < Height())
        Resize(Pt(std::min(Width(), m_max_size.x), std::min(Height(), m_max_size.y)));
}

void Wnd::AttachChild(Wnd* wnd)
{
    if (wnd) {
        // remove from previous parent, if any
        if (wnd->Parent())
            wnd->Parent()->DetachChild(wnd);
        GUI::GetGUI()->Remove(wnd);
        m_children.push_back(wnd);
        wnd->m_parent = this;
        if (Layout* this_as_layout = dynamic_cast<Layout*>(this))
            wnd->m_containing_layout = this_as_layout;
    }
}

void Wnd::MoveChildUp(Wnd* wnd)
{
    if (wnd) {
        if (std::find(m_children.begin(), m_children.end(), wnd) != m_children.end()) {
            m_children.remove(wnd);
            m_children.push_back(wnd);
        }
    }
}
 
void Wnd::MoveChildDown(Wnd* wnd)
{
    if (wnd) {
        if (std::find(m_children.begin(), m_children.end(), wnd) != m_children.end()) {
            m_children.remove(wnd);
            m_children.push_front(wnd);
        }
    }
}

void Wnd::DetachChild(Wnd* wnd)
{
    if (wnd) {
        std::list<Wnd*>::iterator it = std::find(m_children.begin(), m_children.end(), wnd);
        if (it != m_children.end()) {
            m_children.erase(it);
            wnd->m_parent = 0;
            if (Layout* this_as_layout = dynamic_cast<Layout*>(this)) {
                this_as_layout->Remove(wnd);
                wnd->m_containing_layout = 0;
            }
        }
    }
}

void Wnd::DetachChildren()
{
    for (std::list<Wnd*>::iterator it = m_children.begin(); it != m_children.end();) {
        std::list<Wnd*>::iterator temp = it;
        ++it;
        DetachChild(*temp);
    }
}

void Wnd::DeleteChild(Wnd* wnd)
{
    if (wnd && std::find(m_children.begin(), m_children.end(), wnd) != m_children.end()) {
        delete wnd;
    }
}

void Wnd::DeleteChildren()
{
    for (std::list<Wnd*>::iterator it = m_children.begin(); it != m_children.end();) {
        Wnd* wnd = *it++;
        delete wnd;
    }
}

void Wnd::InstallEventFilter(Wnd* wnd)
{
    if (wnd) {
        RemoveEventFilter(wnd);
        m_filters.push_back(wnd);
        wnd->m_filtering.insert(this);
    }
}

void Wnd::RemoveEventFilter(Wnd* wnd)
{
    if (wnd) {
        std::vector<Wnd*>::iterator it = std::find(m_filters.begin(), m_filters.end(), wnd);
        if (it != m_filters.end())
            m_filters.erase(it);
        wnd->m_filtering.erase(this);
    }
}

void Wnd::HorizontalLayout()
{
    RemoveLayout();

    std::multiset<Wnd*, WndHorizontalLess> wnds;
    Pt client_sz = ClientSize();
    for (std::list<Wnd*>::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
        Pt wnd_ul = (*it)->RelativeUpperLeft(), wnd_lr = (*it)->RelativeLowerRight();
        if (wnd_ul.x < 0 || wnd_ul.y < 0 || client_sz.x < wnd_lr.x || client_sz.y < wnd_lr.y)
            continue;
        wnds.insert(*it);
    }

    m_layout = new Layout(0, 0, ClientSize().x, ClientSize().y,
                          1, wnds.size(),
                          DEFAULT_LAYOUT_BORDER_MARGIN, DEFAULT_LAYOUT_CELL_MARGIN);
    AttachChild(m_layout);

    int i = 0;
    for (std::multiset<Wnd*, WndHorizontalLess>::iterator it = wnds.begin(); it != wnds.end(); ++it) {
        m_layout->Add(*it, 0, i++);
    }
}

void Wnd::VerticalLayout()
{
    RemoveLayout();

    std::multiset<Wnd*, WndVerticalLess> wnds;
    Pt client_sz = ClientSize();
    for (std::list<Wnd*>::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
        Pt wnd_ul = (*it)->RelativeUpperLeft(), wnd_lr = (*it)->RelativeLowerRight();
        if (wnd_ul.x < 0 || wnd_ul.y < 0 || client_sz.x < wnd_lr.x || client_sz.y < wnd_lr.y)
            continue;
        wnds.insert(*it);
    }

    m_layout = new Layout(0, 0, ClientSize().x, ClientSize().y,
                          wnds.size(), 1,
                          DEFAULT_LAYOUT_BORDER_MARGIN, DEFAULT_LAYOUT_CELL_MARGIN);
    AttachChild(m_layout);

    int i = 0;
    for (std::multiset<Wnd*, WndVerticalLess>::iterator it = wnds.begin(); it != wnds.end(); ++it) {
        m_layout->Add(*it, i++, 0);
    }
}

void Wnd::GridLayout()
{
    RemoveLayout();

    Pt cl_ul = ClientUpperLeft(), cl_lr = ClientLowerRight();
    Pt client_sz = ClientSize();

    GridLayoutWndContainer grid_layout;

    // validate existing children and place them in a grid with one cell per pixel
    for (std::list<Wnd*>::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
        Wnd* wnd = *it;
        Pt wnd_ul = wnd->RelativeUpperLeft(), wnd_lr = wnd->RelativeLowerRight();
        if (wnd_ul.x < 0 || wnd_ul.y < 0 || client_sz.x < wnd_lr.x || client_sz.y < wnd_lr.y)
            continue;

        std::list<Wnd*>::const_iterator it2 = it;
        ++it2;
        for (; it2 != m_children.end(); ++it2) {
            Rect other_wnd_rect((*it2)->RelativeUpperLeft(), (*it2)->RelativeLowerRight());
            if (other_wnd_rect.Contains(wnd_ul) || other_wnd_rect.Contains(wnd_lr - Pt(1, 1)))
                throw BadLayout("Wnd::GridLayout() : Two or more child windows overlap");
        }

        grid_layout.insert(GridLayoutWnd(wnd, wnd_ul, wnd_lr));
    }


    // align left sides of windows
    for (LeftIter it = grid_layout.get<Left>().begin(); it != grid_layout.get<Left>().end(); ++it) {
        Pt ul = it->ul;
        Pt lr = it->lr;
        for (int x = ul.x - 1; x >= 0; --x) {
            if (grid_layout.get<Right>().find(x + 1, IsRight()) != grid_layout.get<Right>().end()) {
                break;
            } else if (grid_layout.get<Left>().find(x, IsLeft()) != grid_layout.get<Left>().end()) {
                GridLayoutWnd grid_wnd = *it;
                grid_wnd.ul.x = x;
                grid_layout.get<Left>().replace(it, grid_wnd);
                break;
            }
        }
    }

    // align right sides of windows
    for (RightIter it = grid_layout.get<Right>().begin(); it != grid_layout.get<Right>().end(); ++it) {
        Pt ul = it->ul;
        Pt lr = it->lr;
        for (int x = lr.x + 1; x < client_sz.x; ++x) {
            if (grid_layout.get<Left>().find(x - 1, IsLeft()) != grid_layout.get<Left>().end()) {
                break;
            } else if (grid_layout.get<Right>().find(x, IsRight()) != grid_layout.get<Right>().end()) {
                GridLayoutWnd grid_wnd = *it;
                grid_wnd.lr.x = x;
                grid_layout.get<Right>().replace(it, grid_wnd);
                break;
            }
        }
    }

    // align tops of windows
    for (TopIter it = grid_layout.get<Top>().begin(); it != grid_layout.get<Top>().end(); ++it) {
        Pt ul = it->ul;
        Pt lr = it->lr;
        for (int y = ul.y - 1; y >= 0; --y) {
            if (grid_layout.get<Bottom>().find(y + 1, IsBottom()) != grid_layout.get<Bottom>().end()) {
                break;
            } else if (grid_layout.get<Top>().find(y, IsTop()) != grid_layout.get<Top>().end()) {
                GridLayoutWnd grid_wnd = *it;
                grid_wnd.ul.y = y;
                grid_layout.get<Top>().replace(it, grid_wnd);
                break;
            }
        }
    }

    // align bottoms of windows
    for (BottomIter it = grid_layout.get<Bottom>().begin(); it != grid_layout.get<Bottom>().end(); ++it) {
        Pt ul = it->ul;
        Pt lr = it->lr;
        for (int y = lr.y + 1; y < client_sz.y; ++y) {
            if (grid_layout.get<Top>().find(y - 1, IsTop()) != grid_layout.get<Top>().end()) {
                break;
            } else if (grid_layout.get<Bottom>().find(y, IsBottom()) != grid_layout.get<Bottom>().end()) {
                GridLayoutWnd grid_wnd = *it;
                grid_wnd.lr.y = y;
                grid_layout.get<Bottom>().replace(it, grid_wnd);
                break;
            }
        }
    }

    // create an actual layout with a more reasonable number of cells from the pixel-grid layout
    std::set<int> unique_lefts;
    std::set<int> unique_tops;
    for (LeftIter it = grid_layout.get<Left>().begin(); it != grid_layout.get<Left>().end(); ++it) {
        unique_lefts.insert(it->ul.x);
    }
    for (TopIter it = grid_layout.get<Top>().begin(); it != grid_layout.get<Top>().end(); ++it) {
        unique_tops.insert(it->ul.y);
    }

    if (unique_lefts.empty() || unique_tops.empty())
        return;

    m_layout = new Layout(0, 0, ClientSize().x, ClientSize().y,
                          unique_tops.size(), unique_lefts.size(),
                          DEFAULT_LAYOUT_BORDER_MARGIN, DEFAULT_LAYOUT_CELL_MARGIN);
    AttachChild(m_layout);

    // populate this new layout with the child windows, based on their placements in the pixel-grid layout
    for (PointerIter it = grid_layout.get<Pointer>().begin(); it != grid_layout.get<Pointer>().end(); ++it) {
        Wnd* wnd = it->wnd;
        Pt ul = it->ul;
        Pt lr = it->lr;
        int left = std::distance(unique_lefts.begin(), unique_lefts.find(ul.x));
        int top = std::distance(unique_tops.begin(), unique_tops.find(ul.y));
        int right = std::distance(unique_lefts.begin(), unique_lefts.lower_bound(lr.x));
        int bottom = std::distance(unique_tops.begin(), unique_tops.lower_bound(lr.y));
        m_layout->Add(wnd, top, left, bottom - top, right - left);
    }
}

void Wnd::SetLayout(Layout* layout)
{
    if (layout == m_layout && layout == m_containing_layout)
        throw BadLayout("Wnd::SetLayout() : Attempted to set a Wnd's layout to be its current layout or the layout that contains the Wnd");
    RemoveLayout();
    std::list<Wnd*> children = m_children;
    DetachChildren();
    Pt client_sz = ClientSize();
    for (std::list<Wnd*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        Pt wnd_ul = (*it)->RelativeUpperLeft(), wnd_lr = (*it)->RelativeLowerRight();
        if (wnd_ul.x < 0 || wnd_ul.y < 0 || client_sz.x < wnd_lr.x || client_sz.y < wnd_lr.y)
            AttachChild(*it);
        else
            delete *it;
    }
    AttachChild(layout);
    m_layout = layout;
    m_layout->SizeMove(Pt(0, 0), Pt(ClientWidth(), ClientHeight()));
}

void Wnd::RemoveLayout()
{
    if (m_layout) {
        std::list<Wnd*> layout_children = m_layout->Children();
        m_layout->DetachAndResetChildren();
        for (std::list<Wnd*>::iterator it = layout_children.begin(); it != layout_children.end(); ++it) {
            AttachChild(*it);
        }
        DeleteChild(m_layout);
        m_layout = 0;
    }
}

Layout* Wnd::DetachLayout()
{
    Layout* retval = m_layout;
    DetachChild(m_layout);
    m_layout = 0;
    return retval;
}

void Wnd::SetLayoutBorderMargin(int margin)
{
    if (m_layout)
        m_layout->SetBorderMargin(margin);
}

void Wnd::SetLayoutCellMargin(int margin)
{
    if (m_layout)
        m_layout->SetCellMargin(margin);
}

void Wnd::Render() {}

void Wnd::LButtonDown(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::LDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys) {if (Dragable()) OffsetMove(move);}

void Wnd::LButtonUp(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::LClick(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::LDoubleClick(const Pt& pt, Flags<ModKey> mod_keys) {LClick(pt, mod_keys);}

void Wnd::RButtonDown(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::RClick(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::RDoubleClick(const Pt& pt, Flags<ModKey> mod_keys) {RClick(pt, mod_keys);}

void Wnd::MouseEnter(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::MouseHere(const Pt& pt, Flags<ModKey> mod_keys) {}

void Wnd::MouseLeave() {}

void Wnd::MouseWheel(const Pt& pt, int move, Flags<ModKey> mod_keys) {}

void Wnd::DragDropEnter(const Pt& pt, const std::map<Wnd*, Pt>& drag_drop_wnds, Flags<ModKey> mod_keys) {}

void Wnd::DragDropHere(const Pt& pt, const std::map<Wnd*, Pt>& drag_drop_wnds, Flags<ModKey> mod_keys) {}

void Wnd::DragDropLeave() {}

void Wnd::KeyPress(Key key, Flags<ModKey> mod_keys) {}

void Wnd::KeyRelease(Key key, Flags<ModKey> mod_keys) {}

void Wnd::GainingFocus() {}

void Wnd::LosingFocus() {}

void Wnd::TimerFiring(int ticks, Timer* timer) {}

int Wnd::Run()
{
    int retval = 0;
    if (m_flags & MODAL) {
        GUI* gui = GUI::GetGUI();
        gui->RegisterModal(this);
        ModalInit();
        boost::shared_ptr<ModalEventPump> pump = gui->CreateModalEventPump(m_done);
        (*pump)();
        gui->Remove(this);
        retval = 1;
    }
    return retval;
}

void Wnd::SetBrowseModeTime(int time, int mode/* = 0*/)
{
    if (static_cast<int>(m_browse_modes.size()) <= mode) {
        if (m_browse_modes.empty()) {
            m_browse_modes.resize(mode + 1);
            for (unsigned int i = 0; i < m_browse_modes.size() - 1; ++i) {
                m_browse_modes[i].time = time;
            }
        } else {
            unsigned int original_size = m_browse_modes.size();
            m_browse_modes.resize(mode + 1);
            for (unsigned int i = original_size; i < m_browse_modes.size() - 1; ++i) {
                m_browse_modes[i].time = m_browse_modes[original_size - 1].time;
            }
        }
    }
    m_browse_modes[mode].time = time;
}

void Wnd::SetBrowseInfoWnd(const boost::shared_ptr<BrowseInfoWnd>& wnd, int mode/* = 0*/)
{
    m_browse_modes.at(mode).wnd = wnd;
}

void Wnd::SetBrowseText(const std::string& text, int mode/* = 0*/)
{
    m_browse_modes.at(mode).text = text;
}

void Wnd::SetBrowseModes(const std::vector<BrowseInfoMode>& modes)
{
    m_browse_modes = modes;
}

void Wnd::SetStyleFactory(const boost::shared_ptr<StyleFactory>& factory)
{
    m_style_factory = factory;
}

void Wnd::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    editor->Label("Wnd");
    boost::shared_ptr<SetWindowTextAction> action(new SetWindowTextAction(this));
    editor->Attribute<std::string>("Window Text", m_text, action);
    editor->ConstAttribute("Upper Left", m_upperleft);
    editor->ConstAttribute("Lower Right", m_lowerright);
    editor->CustomText("Size", WndSizeFunctor());
    editor->CustomText("Client Size", WndClientSizeFunctor());
    editor->Attribute("Min Size", m_min_size);
    editor->Attribute("Max Size", m_max_size);
    editor->Attribute("Clip Children", m_clip_children);
    editor->Attribute("Drag Drop Type", m_drag_drop_data_type);
    editor->BeginFlags(m_flags);
    editor->Flag("Clickable", CLICKABLE);
    editor->Flag("Dragable", DRAGABLE);
    editor->Flag("Resizable", RESIZABLE);
    editor->Flag("Ontop", ONTOP);
    editor->Flag("Modal", MODAL);
    editor->EndFlags();
    // TODO: handle creation and modification of browse info modes
}

int Wnd::DefaultBrowseTime()
{
    return s_default_browse_time;
}

void Wnd::SetDefaultBrowseTime(int time)
{
    s_default_browse_time = time;
}

const boost::shared_ptr<BrowseInfoWnd>& Wnd::DefaultBrowseInfoWnd()
{
    return s_default_browse_info_wnd;
}

void Wnd::SetDefaultBrowseInfoWnd(const boost::shared_ptr<BrowseInfoWnd>& browse_info_wnd)
{
    s_default_browse_info_wnd = browse_info_wnd;
}

bool Wnd::EventFilter(Wnd* w, const WndEvent& event)
{
    return false;
}

void Wnd::HandleEvent(const WndEvent& event)
{
    for (int i = static_cast<int>(m_filters.size()) - 1; i >= 0; --i) {
        if (m_filters[i]->EventFilter(this, event))
            return;
    }

    switch (event.Type()) {
    case WndEvent::LButtonDown:
        LButtonDown(event.Point(), event.ModKeys());
        break;
    case WndEvent::LDrag:
        LDrag(event.Point(), event.DragMove(), event.ModKeys());
        break;
    case WndEvent::LButtonUp:
        LButtonUp(event.Point(), event.ModKeys());
        break;
    case WndEvent::LClick:
        LClick(event.Point(), event.ModKeys());
        break;
    case WndEvent::LDoubleClick:
        LDoubleClick(event.Point(), event.ModKeys());
        break;
    case WndEvent::RButtonDown:
        RButtonDown(event.Point(), event.ModKeys());
        break;
    case WndEvent::RClick:
        RClick(event.Point(), event.ModKeys());
        break;
    case WndEvent::RDoubleClick:
        RDoubleClick(event.Point(), event.ModKeys());
        break;
    case WndEvent::MouseEnter:
        MouseEnter(event.Point(), event.ModKeys());
        break;
    case WndEvent::MouseHere:
        MouseHere(event.Point(), event.ModKeys());
        break;
    case WndEvent::MouseLeave:
        MouseLeave();
        break;
    case WndEvent::DragDropEnter:
        DragDropEnter(event.Point(), event.DragDropWnds(), event.ModKeys());
        break;
    case WndEvent::DragDropHere:
        DragDropHere(event.Point(), event.DragDropWnds(), event.ModKeys());
        break;
    case WndEvent::DragDropLeave:
        DragDropLeave();
        break;
    case WndEvent::MouseWheel:
        MouseWheel(event.Point(), event.WheelMove(), event.ModKeys());
        break;
    case WndEvent::KeyPress:
        KeyPress(event.GetKey(), event.ModKeys());
        break;
    case WndEvent::KeyRelease:
        KeyRelease(event.GetKey(), event.ModKeys());
        break;
    case WndEvent::GainingFocus:
        GainingFocus();
        break;
    case WndEvent::LosingFocus:
        LosingFocus();
        break;
    case WndEvent::TimerFiring:
        TimerFiring(event.Ticks(), event.GetTimer());
        break;
    default:
        break;
    }
}

void Wnd::ValidateFlags()
{
    if ((m_flags & MODAL) && (m_flags & ONTOP))
        m_flags &= ~ONTOP;
}




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