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_label.cpp -- GLabel implementation

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

#include "gui_label.h"


/*
==============
GLabel::GLabel

Initialize everything
==============
*/
GLabel::GLabel(GPanel *pParent, int x, int y, int w, int h, const char *szText, int iAlign)
    : GPanel(pParent, x, y, w, h)
{
    m_pszText = 0;
    m_pFont = 0;
    m_pPic = 0,
    m_pSprite = 0;

    m_iAlign = iAlign;
    m_iYSpacing = 0;

    m_iBorderX = m_iBorderY = 0;
    m_iScrollX = m_iScrollY = 0;

    if (szText)
        SetText(szText);
}

GLabel::GLabel(GPanel *pParent, const char *szPic, int type, u32 colorkey,
               int x, int y, int w, int h)
    : GPanel(pParent, x, y, w, h)
{
    m_pszText = 0;
    m_pFont = 0;
    m_pPic = 0;
    m_pSprite = 0;

    m_iAlign = 0;
    m_iYSpacing = 0;

    m_iBorderX = m_iBorderY = 0;
    m_iScrollX = m_iScrollY = 0;

    if (szPic)
        SetPicture(szPic, type, colorkey);
}

/*
==============
GLabel::~GLabel

Free allocated resources
==============
*/
GLabel::~GLabel()
{
    Clear();
}

/*
==============
GLabel::Clear

Clears text or picture or sprite
==============
*/
void GLabel::Clear()
{
    if (m_pPic) {
        m_pPic->Release();
        m_pPic = 0;
    }
    if (m_pszText) {
        L_Free(m_pszText);
        m_pszText = 0;
    }
    if (m_pSprite) {
        SPR_Free(m_pSprite);
        m_pSprite = 0;
    }
    if (m_pFont) {
        m_pFont->Release();
        m_pFont = 0;
    }
}

/*
==============
GLabel::SetText

Replace the label's text with a new one. pszText can be 0
==============
*/
void GLabel::SetText(const char *pszText)
{
    Clear();

    if (pszText) {
        m_pszText = L_Strdup(pszText, TAG_GUI);
        if (!m_pFont)
            m_pFont = HFont::Get("font");
    }
}

/*
==============
GLabel::SetPicture

Replace the current picture with a new one.
Ownership is not transferred in the direct version.
==============
*/
void GLabel::SetPicture(const char *szPic, int type, u32 colorkey)
{
    Clear();

    if (szPic)
        m_pPic = HPicture::Get(szPic, type, colorkey);
}

void GLabel::SetPicture(HPicture *pPic)
{
    Clear();

    if (pPic) {
        m_pPic = pPic;
        pPic->AddRef();
    }
}

/*
==============
GLabel::SetSprite

Makes the label display the given sprite.
Ownership is not transferred in the direct version
==============
*/
void GLabel::SetSprite(const char *szSprite)
{
    Clear();

    if (szSprite)
        m_pSprite = SPR_Get(szSprite);
}

void GLabel::SetSprite(sprite_t *sprite)
{
    Clear();

    if (sprite) {
        m_pSprite = sprite;
        m_pSprite->used++;
    }
}

/*
==============
GLabel::SetAlign

Change the label's alignment
==============
*/
void GLabel::SetAlign(int iAlign)
{
    m_iAlign = iAlign;
}

/*
==============
GLabel::SetBorder

Designates a border which is kept free of text.
==============
*/
void GLabel::SetBorder(int x, int y)
{
    m_iBorderX = x;
    m_iBorderY = y;
}

/*
==============
GLabel::AdjustSize

Adjust the size to fit the text exactly without moving the
point of alignment
==============
*/
void GLabel::AdjustSize()
{
    int iw, ih;
    int w, h;

    if (m_pszText) {
        m_pFont->StringSize(m_pszText, (m_iAlign & align_wrap) ? m_rc.size[0] : -1,
                m_iYSpacing, &w, &h);
    } else if (m_pPic) {
        w = m_pPic->size[0];
        h = m_pPic->size[1];
    } else
        return; // adjustsize for sprites? problematic with animations

    GetIconSize(&iw, &ih);

    if (iw)
        w += iw + 8; // 8 pxls of additional spacing
    if (ih > h)
        h = ih;

    w += m_iBorderX*2;
    h += m_iBorderY*2;

    switch(m_iAlign & halign_mask) {
    case halign_center:
        m_rc.pos[0] += (m_rc.size[0] - w) / 2;
        break;

    case halign_right:
        m_rc.pos[0] += m_rc.size[0] - w;
        break;
    }
    m_rc.size[0] = w;

    switch(m_iAlign & valign_mask) {
    case valign_center:
        m_rc.pos[1] += (m_rc.size[1] - h) / 2;
        break;

    case valign_bottom:
        m_rc.pos[1] += m_rc.size[1] - h;
        break;
    }
    m_rc.size[1] = h;
}

/*
==============
GLabel::Draw

Render the text or picture
==============
*/
void GLabel::Draw()
{
    doDraw(m_color[0], m_color[1], m_color[2], m_color[3]);
}

/*
==============
GLabel::GetDrawPoint

Retrieves the point at which the text is drawn - depends on alignment
==============
*/
void GLabel::GetDrawPoint(int *x, int *y)
{
    int ofsx, ofsy;
    int w, h;
    int iw, ih;

    w = m_rc.size[0] - m_iBorderX*2;
    h = m_rc.size[1] - m_iBorderY*2;
    ofsx = m_iBorderX;
    ofsy = m_iBorderY;

    GetIconSize(&iw, &ih);
    if (iw > 0) {
        w -= iw + 8;
        ofsx += iw + 8;
    }

    switch(m_iAlign & halign_mask) {
    default:
    case halign_left: *x = 0; break;
    case halign_center: *x = w / 2; break;
    case halign_right: *x = w; break;
        break;
    }
    *x += ofsx;
    *x -= m_iScrollX;

    switch(m_iAlign & valign_mask) {
    default:
    case valign_top: *y = 0; break;
    case valign_center: *y = h / 2; break;
    case valign_bottom: *y = h; break;
    }
    *y += ofsy;
    *y -= m_iScrollY;
}

/*
==============
GLabel::doDraw

Put in its own function so derived classes can easily customize
the behaviour
==============
*/
void GLabel::doDraw(int r, int g, int b, int a)
{
    int x, y;
    int iw, ih;

    GetDrawPoint(&x, &y);

    if (m_pszText) {
        if (m_pFont)
            m_pFont->DrawString(x, y, m_pszText, m_iAlign, m_rc.size[0], m_iYSpacing,
                                r, g, b, a);
    } else if (m_pPic) {
        switch(m_iAlign & halign_mask) {
        case halign_center: x -= m_pPic->size[0] / 2; break;
        case halign_right: x -= m_pPic->size[0]; break;
        }

        switch(m_iAlign & valign_mask) {
        case valign_center: y -= m_pPic->size[1] / 2; break;
        case valign_bottom: y -= m_pPic->size[1]; break;
        }

        m_pPic->Draw(x, y, r, g, b, a);
    } else if (m_pSprite) {
        SPR_Draw(m_pSprite, x, y, -1, hal->framestart);
    }

    GetIconSize(&iw, &ih);

    x = m_iBorderX + iw/2;
    y = m_rc.size[1] / 2;

    DrawIcon(x, y, r, g, b, a);
}

/*
==============
GLabel::GetCharRect

Return the enclosing rectangle for the given character
==============
*/
void GLabel::GetCharRect(int idx, LRect *rc)
{
    int x, y;

    GetDrawPoint(&x, &y);

    if (!m_pszText || idx < 0) { // rc before the first char
        rc->pos[0] = x;
        rc->pos[1] = y;

        switch(m_iAlign & valign_mask) {
        case valign_center: rc->pos[1] -= 8; break;
        case valign_bottom: rc->pos[1] -= 16; break;
        }

        rc->size[0] = 0;
        rc->size[1] = 16;
    } else {
        m_pFont->CharRect(m_pszText, idx, m_iAlign, m_rc.size[0], m_iYSpacing, rc);
        rc->pos[0] += x;
        rc->pos[1] += y;
    }
}

/*
==============
GLabel::GetIconSize

Return the size of the built-in icon (for radio-buttons)
==============
*/
void GLabel::GetIconSize(int *pw, int *ph)
{
    *pw = 0; // normal labels don't have an icon
    *ph = 0;
}

/*
==============
GLabel::DrawIcon

Draw the built-in icon (for radio-buttons)
==============
*/
void GLabel::DrawIcon(int x, int y, int r, int g, int b, int a)
{
}