Code Search for Developers
 
 
  

ZList.cpp from FreeOrion at Krugle


Show ZList.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/ZList.h>
#include <GG/Wnd.h>

using namespace GG;

namespace {
    const int DESIRED_GAP_SIZE = 10;       // leaves room for 10-deep nested child windows (and that should be plenty)
    const int DESIRED_LOWEST_Z = 1 << 30;  // start z-values at 1/4 of 32-bit int's positive range (2^32 / 4 = 2^30)
    const int MIN_Z = 1 << 28;             // set low end of z-value range at 1/16 of 32-bit int's range (2^32 / 16 = 2^28)
    const int MAX_Z = 7 * MIN_Z;           // set high end of z-value range at 7/16 of 32-bit int's range (7 * 2^32 / 16 = 7 * 2^28)
    const int MAX_AVG_GAP_SIZE = 15;       // if things get too spread out..
    const int MIN_AVG_GAP_SIZE = 5;        // ..or too packed, compresion may be needed
    const int MAX_SPAN = 1 << 31;          // windows should be laid out over no more than 1/2 of possible z-value range (2^32 / 2 = 2^31)
}

///////////////////////////////////////
// class GG::ZList
///////////////////////////////////////
Wnd* ZList::Pick(const Pt& pt, Wnd* modal, Wnd* ignore/* = 0*/) const
{
    Wnd* retval = 0;
    if (modal) { // if a modal window is active, only look there
        // NOTE: We have to check Visible() separately, because in the rendering code a invisble parent's children are
        // never rendered.
        retval = modal->Visible() && modal->InWindow(pt) ? PickWithinWindow(pt, modal, ignore) : 0;
    } else { // otherwise, look in the z-list
        const_iterator end_it = end();
        for (const_iterator it = begin(); it != end_it; ++it) {
            Wnd* temp = 0;
            if ((*it)->Visible() && (*it)->InWindow(pt) && (temp = PickWithinWindow(pt, *it, ignore))) {
                retval = temp;
                break;
            }
        }
    }
    return retval;
}

void ZList::Add(Wnd* wnd)
{
    if (m_contents.find(wnd) == m_contents.end()) {
        // add wnd to the end of the list...
        if (empty()) { // list empty
            wnd->m_zorder = DESIRED_LOWEST_Z; // by default, add first element at DESIRED_LOWEST_Z
            insert(begin(), wnd);
        } else { // list not empty
            wnd->m_zorder = back()->m_zorder - (DESIRED_GAP_SIZE + 1);
            insert(end(), wnd);
        }
        m_contents.insert(wnd);
        // then move it up to its proper place
        MoveUp(wnd);
        if (NeedsRealignment()) Realign();
    }
}

bool ZList::Remove(Wnd* wnd)
{
    bool retval = false;
    if (m_contents.find(wnd) != m_contents.end()) {
        iterator it = std::find(begin(), end(), wnd);
        if (it != end())
            erase(it);
        if (NeedsRealignment()) Realign();
        m_contents.erase(wnd);
        retval = true;
    }
    return retval;
}

bool ZList::MoveUp(Wnd* wnd)
{
    bool retval = false;
    iterator it = std::find(begin(), end(), wnd);
    if (it != end()) { // note that this also implies !empty()..
        int top_z = front()->m_zorder; // ..so this is okay to do without checking
        if (!front()->OnTop() || wnd->OnTop()) { // if there are no on-top windows, or wnd is an on-top window..
            (*it)->m_zorder = top_z + DESIRED_GAP_SIZE + 1; // ..just slap wnd on top of the topmost element
            splice(begin(), *this, it);
        } else { // front()->OnTop() && !wnd->OnTop(), so only move wnd up to just below the bottom of the on-top range
            iterator first_non_ontop_it = FirstNonOnTop();
            int prev_z = (*--first_non_ontop_it)->m_zorder;
            int curr_z = (*++first_non_ontop_it)->m_zorder;
            if (prev_z - curr_z - 1 >= 3) { // if there's at least 3 positions in between..
                (*it)->m_zorder = (*first_non_ontop_it)->m_zorder + (prev_z - curr_z - 1) / 2; // ..just stick wnd in the middle
                splice(first_non_ontop_it, *this, it);
            } else { // make room by bumping up all the on-top windows
                iterator it2 = first_non_ontop_it;
                (*--it2)->m_zorder += 2 * (DESIRED_GAP_SIZE + 1); // double the gap before first_non_ontop_it, to leave the right gap on either side of wnd
                while (it2 != begin()) {
                    --it2;
                    (*it2)->m_zorder += DESIRED_GAP_SIZE + 1;
                }
                (*it)->m_zorder = (*first_non_ontop_it)->m_zorder + DESIRED_GAP_SIZE + 1;
                splice(first_non_ontop_it, *this, it);
            }
        }
        retval = true;
    }
    if (NeedsRealignment()) Realign();
    return retval;
}

bool ZList::MoveDown(Wnd* wnd)
{
    bool retval = false;
    iterator it = std::find(begin(), end(), wnd);
    if (it != end()) {
        int bottom_z = back()->m_zorder;
        if (back()->OnTop() || !wnd->OnTop()) { // if there are only on-top windows, or wnd is not an on-top window..
            (*it)->m_zorder = bottom_z - (DESIRED_GAP_SIZE + 1); // ..just put wnd below the bottom element
            splice(end(), *this, it);
        } else { // !back()->OnTop() && wnd->OnTop(), so only move wnd up to just below the bottom of the on-top range
            iterator first_non_ontop_it = FirstNonOnTop();
            int prev_z = (*--first_non_ontop_it)->m_zorder;
            int curr_z = (*++first_non_ontop_it)->m_zorder;
            if (prev_z - curr_z - 1 >= 3) { // if there's at least 3 positions in between..
                (*it)->m_zorder = (*first_non_ontop_it)->m_zorder + (prev_z - curr_z - 1) / 2; // ..just stick wnd in the middle
                splice(first_non_ontop_it, *this, it);
            } else { // make room by bumping up all the on-top windows
                iterator it2 = first_non_ontop_it;
                (*--it2)->m_zorder += 2 * (DESIRED_GAP_SIZE + 1); // double the gap before first_non_ontop_it, to leave the right gap on either side of wnd
                while (it2 != begin()) {
                    --it2;
                    (*it2)->m_zorder += DESIRED_GAP_SIZE + 1;
                }
                (*it)->m_zorder = (*first_non_ontop_it)->m_zorder + DESIRED_GAP_SIZE + 1;
                splice(first_non_ontop_it, *this, it);
            }
        }
        retval = true;
    }
    if (NeedsRealignment()) Realign();
    return retval;
}

Wnd* ZList::PickWithinWindow(const Pt& pt, Wnd* wnd, Wnd* ignore) const
{
    // if wnd is visible and clickable, return it if no child windows also catch pt
    Wnd* retval = (wnd->Visible() && wnd->Clickable() && wnd != ignore) ? wnd : 0;
    // look through all the children of wnd, and determine whether pt lies in any of them (or their children)
    std::list<Wnd*>::reverse_iterator end_it = wnd->m_children.rend();
    for (std::list<Wnd*>::reverse_iterator it = wnd->m_children.rbegin(); it != end_it; ++it) {
        Wnd* temp = 0;
        if ((*it)->InWindow(pt) && (temp = PickWithinWindow(pt, *it, ignore))) {
            retval = temp;
            break;
        }
    }
    return retval;
}

bool ZList::NeedsRealignment() const
{
    bool retval = false;
    if (unsigned int sz = size()) {
        int front_z = front()->m_zorder;
        int back_z = back()->m_zorder;
        int range = front_z - back_z + 1;
        int empty_slots = range - sz;
        double avg_gap = empty_slots / static_cast<double>(sz - 1); // empty slots over the number of spaces in between the elements
        bool max_span_impossible = DESIRED_GAP_SIZE * static_cast<double>(sz) > MAX_SPAN; // done with doubles to avoid integer overflow
        retval = ((range > MAX_SPAN && !max_span_impossible) ||
                  avg_gap > MAX_AVG_GAP_SIZE ||
                  avg_gap < MIN_AVG_GAP_SIZE ||
                  front_z > MAX_Z ||
                  back_z < MIN_Z);
    }
    return retval;
}

void ZList::Realign()
{
    int z = DESIRED_LOWEST_Z; // z-value to place next element at
    for (reverse_iterator it = rbegin(); it != rend(); ++it) {
        (*it)->m_zorder = z;
        z += DESIRED_GAP_SIZE + 1;
    }
}

ZList::iterator ZList::FirstNonOnTop()
{
    iterator retval = begin();
    for (; retval != end(); ++retval)
        if (!(*retval)->OnTop())
            break;
    return retval;
}




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