If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle

See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// gui_popupmenu.cpp -- popup-menu specialization

#include "library.h"
#include "hal.h"

#include "gui_popupmenu.h"


/*
==============================================================================

GPopupMenu IMPLEMENTATION

==============================================================================
*/

/*
===============
GPopupMenu::GPopupMenu

Initialize a popup menu
===============
*/
GPopupMenu::GPopupMenu()
    : GMenu(0, 0, 0, 0, 0)
{
    SetCanFocus(true);
    SetVisible(false);
    SetTopLevel(true);
}

/*
===============
GPopupMenu::~GPopupMenu

Cleanup menu data
===============
*/
GPopupMenu::~GPopupMenu()
{
}

/*
===============
GPopupMenu::Display

Display the menu at the given location. The menu can be moved to make sure it
fits onto the screen.
===============
*/
void GPopupMenu::Display(int x, int y)
{
    int w, h;

    // set size
    w = 0;
    h = 0;

    for(GMenuItem::v_it item = m_MenuItems.begin(); item != m_MenuItems.end(); item++) {
        if ((*item)->GetWidth() > w)
            w = (*item)->GetWidth();

        h += (*item)->GetHeight();
    }

    SetSize(w, h);

    // set position
    if (x < 0)
        x = 0;
    if (y < 0)
        y = 0;

    if (x+w > 640)
        x = 640-w;
    if (y+h > 480)
        y = 480-h;

    SetPos(x, y);

    // run the whole thing
    SetVisible(true);
    m_iHighlighted = -1;
    int code = Run();
    SetVisible(false);

    if (code >= 0 && code < m_MenuItems.size()) {
        GMenuItem *pItem = m_MenuItems[code];
        pItem->signaled.Emit();
    }
}

/*
===============
GPopupMenu::DisplayNearMouse

Convenience function that will display the menu near the mouse (useful for
context menus)
===============
*/
void GPopupMenu::DisplayNearMouse()
{
    int mx, my;

    hal->GetMouseState(&mx, &my);

    Display(mx, my);
}

/*
===============
GPopupMenu::Begin

Grab the mouse when we get modal. This way, we get mouse-click even outside
the menu.

If a hierarchy of popupmenus is running, then the topmost menu should be
modal and own the mousegrab.
===============
*/
void GPopupMenu::Begin()
{
    GrabMouse(true);
}

void GPopupMenu::End()
{
    GrabMouse(false);
}

/*
===============
GPopupMenu::Draw

Draw all the menu items
===============
*/
void GPopupMenu::Draw()
{
    hal->FillRect(0, 0, m_rc.size[0], m_rc.size[1], 0, 0, 0, 200);

    int y = 0;
    for(GMenuItem::v_it item = m_MenuItems.begin(); item != m_MenuItems.end(); item++) {
        (*item)->Draw(0, y, (item-m_MenuItems.begin()) == m_iHighlighted);
        y += (*item)->GetHeight();
    }
}

/*
===============
GPopupMenu::MouseButton

Left-click activates the currently highlighted item and quits the menu
===============
*/
bool GPopupMenu::MouseButton(int btn, int x, int y, bool down)
{
    if (!IsMouseOver()) {
        EndModal(-1);
        return true;
    }

    TrackMouse(x, y);

    if (btn == 0)
    {
        if (!down && m_iHighlighted >= 0)
            EndModal(m_iHighlighted);

        return true;
    }

    return false;
}

/*
===============
GPopupMenu::MouseMove

Track the highlight
===============
*/
void GPopupMenu::MouseMove(int x, int y)
{
    TrackMouse(x, y);
}

/*
===============
GPopupMenu::TrackMouse

Set the highlight depending on the current mouse pos
===============
*/
void GPopupMenu::TrackMouse(int x, int y)
{
    if (x >= 0 && x < m_rc.size[0] && y >= 0 && y < m_rc.size[0])
    {
        int h = 0;
        for(GMenuItem::v_it item = m_MenuItems.begin(); item != m_MenuItems.end(); item++) {
            h += (*item)->GetHeight();
            if (y < h) {
                m_iHighlighted = item - m_MenuItems.begin();
                return;
            }
        }
    }

    m_iHighlighted = -1;
}