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_listbox.cpp

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

#include "gui_listbox.h"


/*
==============
GListBox::GListBox

Initialize an empty listbox
==============
*/
GListBox::GListBox(GPanel *pParent, int x, int y, int w, int h)
    : GPanel(pParent, x, y, w, h)
{
    SetCanFocus(true);

    m_iNumItems = 0;
    m_pItems = 0;

    m_iSelection = -1;

    m_selectedcolor[0] = 255;
    m_selectedcolor[1] = 0;
    m_selectedcolor[2] = 0;
    m_selectedcolor[3] = 255;

    m_pFont = HFont::Get("font");
}

/*
==============
GListBox::~GListBox

Free all items
==============
*/
GListBox::~GListBox()
{
    int i;

    for(i = 0; i < m_iNumItems; i++)
        L_Free(m_pItems[i]);
    if (m_pItems)
        L_Free(m_pItems);

    m_pFont->Release();
}

/*
==============
GListBox::AddString

Add a new selection to the end of the list
==============
*/
void GListBox::AddString(const char *sz)
{
    m_pItems = (char **)L_Realloc(m_pItems, sizeof(char *)*(m_iNumItems+1), TAG_GUI);
    m_pItems[m_iNumItems++] = L_Strdup(sz, TAG_GUI);
}

/*
==============
GListBox::GetSelection

Returns the currently selected string or 0 if nothing is selected
==============
*/
const char *GListBox::GetSelection()
{
    if (m_iSelection < 0)
        return 0;
    return m_pItems[m_iSelection];
}

/*
==============
GListBox::SelectMove

Move the selection up or down
==============
*/
void GListBox::SelectMove(int d)
{
    if (!m_iNumItems || !d)
        return;

    m_iSelection += d;
    if (m_iSelection < 0)
        m_iSelection = 0;
    if (m_iSelection >= m_iNumItems)
        m_iSelection = m_iNumItems - 1;

    SelectChanged.Emit();
}

/*
==============
GListBox::SetSelection

Moves the selection to a specific item
==============
*/
void GListBox::SetSelection(int id)
{
    lassert(id >= 0 && id < m_iNumItems);

    if (m_iSelection == id)
        return;

    m_iSelection = id;

    SelectChanged.Emit();
}

/*
==============
GListBox::Draw

Print all strings and draw a border around them
==============
*/
void GListBox::Draw()
{
    int i;
    int y;

    y = 4;
    for(i = 0; i < m_iNumItems; i++) {
        byte *color;

        if (i == m_iSelection)
            color = m_selectedcolor;
        else
            color = m_color;

        m_pFont->DrawString(4, y, m_pItems[i], 0, -1, 0,
                color[0], color[1], color[2], color[3]);

        y += 16;
    }

    hal->DrawLine(0, 0, m_rc.size[0], 0, m_color[0], m_color[1], m_color[2], m_color[3]);
    hal->DrawLine(m_rc.size[0], 0, m_rc.size[0], m_rc.size[1], m_color[0], m_color[1], m_color[2], m_color[3]);
    hal->DrawLine(m_rc.size[0], m_rc.size[1], 0, m_rc.size[1], m_color[0], m_color[1], m_color[2], m_color[3]);
    hal->DrawLine(0, m_rc.size[1], 0, 0, m_color[0], m_color[1], m_color[2], m_color[3]);
}

/*
==============
GListBox::Key

Up/down changes the selection
==============
*/
bool GListBox::Key(int code, char c, bool down)
{
    if (down) {
        switch(code) {
        case KEY_UP:
            SelectMove(-1);
            return true;
        case KEY_DOWN:
            SelectMove(1);
            return true;
        }
    }

    return GPanel::Key(code, c, down);
}

/*
==============
GListBox::MouseButton

Single-click to select an item
==============
*/
bool GListBox::MouseButton(int btn, int x, int y, bool down)
{
    if (down && btn == 0) {
        y -= 4;
        y = y / 16;

        if (y >= 0 && y < m_iNumItems)
            SetSelection(y);

        if (!IsFocussed() && CanFocus())
            m_pParent->SetFocus(this);

        return true;
    }

    return GPanel::MouseButton(btn, x, y, down);
}