File StackPanelWidget.c

File List > engine > src > gameframework > layers > UI > widgets > StackPanelWidget.c

Go to the documentation of this file

#include "StackPanelWidget.h"
#include "Widget.h"
#include <stdlib.h>
#include "AssertLib.h"
#include <string.h>
#include "DataNode.h"

void StackPanel_PopulateDataFromXML(struct DataNode* pNode, struct StackPanelWidgetData* pData)
{
    if(pNode->fnGetPropType(pNode, "orientation") == DN_String)
    {
        if(pNode->fnStrCmp(pNode, "orientation", "horizontal"))
        {
            pData->orientation = SPO_Horizontal;
        }
        else if (pNode->fnStrCmp(pNode, "orientation", "vertical"))
        {
            pData->orientation = SPO_Vertical;
        }
        else
        {
            pData->orientation = SPO_Vertical;
        }
    }
}

float StackPanel_GetWidth(struct UIWidget* pWidget, struct UIWidget* pParent, struct StackPanelWidgetData* pStackPanelData)
{
    float width = 0.0;

    if (pWidget->hFirstChild == NULL_HWIDGET)
    {
        return width;
    }
    switch (pStackPanelData->orientation)
    {
    case SPO_Horizontal:
    {
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            width += pChild->fnGetWidth(pChild, pWidget);
            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }
        break;
    }
    case SPO_Vertical:
    {
        float widest = 0.0;
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            float thisChildW = pChild->fnGetWidth(pChild, pWidget);
            if (thisChildW > widest)
            {
                widest = thisChildW;
            }
            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }
        width = widest;
        break;
    }
    }
    return width + pWidget->padding.paddingLeft + pWidget->padding.paddingRight;
}

float StackPanel_GetHeight(struct UIWidget* pWidget, struct UIWidget* pParent, struct StackPanelWidgetData* pStackPanelData)
{
    float height = 0.0;

    if (pWidget->hFirstChild == NULL_HWIDGET)
    {
        return height;
    }
    switch (pStackPanelData->orientation)
    {
    case SPO_Horizontal:
    {
        float tallest = 0.0;
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            float thisChildH = pChild->fnGetHeight(pChild, pWidget);
            if (thisChildH > tallest)
            {
                tallest = thisChildH;
            }
            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }
        height = tallest;
        break;
    }
    case SPO_Vertical:
    {
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            height += pChild->fnGetHeight(pChild, pWidget);
            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }
        break;
    }
    }
    return height + pWidget->padding.paddingTop + pWidget->padding.paddingBottom;
}

void StackPanel_LayoutChildren(struct UIWidget* pWidget, struct UIWidget* pParent, struct StackPanelWidgetData* pStackPanelData, float w, float h)
{
    if (pWidget->hFirstChild == NULL_HWIDGET)
    {
        return;
    }

    float top = pWidget->top + pWidget->padding.paddingTop;
    float left = pWidget->left + pWidget->padding.paddingLeft;


    switch (pStackPanelData->orientation)
    {
    case SPO_Horizontal:
    {
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            float childHeight = pChild->fnGetHeight(pChild, pWidget);
            if (childHeight == h)
            {
                pChild->left = left;
                pChild->top = top;
                left += pChild->fnGetWidth(pChild, pWidget);
            }
            else
            {
                EASSERT(childHeight < h);
                switch(pChild->verticalAlignment)
                {
                case WVA_Middle:
                    pChild->top = top + (h - childHeight) * 0.5;
                    break;
                case WVA_Bottom:
                    pChild->top = top + (h - childHeight);
                    break;
                case WVA_Top:
                    pChild->top = top;
                    break;
                default:
                    EASSERT(false);
                    break;
                }
                pChild->left = left;
                left += pChild->fnGetWidth(pChild, pWidget);

            }

            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }

        break;
    }
    case SPO_Vertical:
    {
        struct UIWidget* pChild = UI_GetWidget(pWidget->hFirstChild);
        while (pChild)
        {
            float childWidth = pChild->fnGetWidth(pChild, pWidget);
            if (childWidth == w)
            {
                pChild->left = left;
                pChild->top = top;
                top += pChild->fnGetHeight(pChild, pWidget);
            }
            else
            {
                EASSERT(childWidth < w);
                switch(pChild->horizontalAlignment)
                {
                case WHA_Left:
                    pChild->left = left;
                    break;
                case WHA_Middle:
                    pChild->left = left + (w - childWidth) * 0.5f;
                    break;
                case WHA_Right:
                    pChild->left = left + (w - childWidth);
                    break;
                }
                pChild->top = top;
                top += pChild->fnGetHeight(pChild, pWidget);
            }

            if (pChild->hNext == NULL_HWIDGET)
            {
                pChild = NULL;
            }
            else
            {
                pChild = UI_GetWidget(pChild->hNext);
            }
        }
        break;
    }
    }
    UI_Helper_OnLayoutChildren(pWidget, pParent);
}

static float GetWidth(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    return StackPanel_GetWidth(pWidget, pParent, pWidget->pImplementationData);
}

static float GetHeight(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    return StackPanel_GetHeight(pWidget, pParent, pWidget->pImplementationData);
}

static void LayoutChildren(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    struct StackPanelWidgetData* pStackPanelData = pWidget->pImplementationData;
    StackPanel_LayoutChildren(pWidget, pParent, pStackPanelData, GetWidth(pWidget, pParent), GetHeight(pWidget, pParent));
}

static void OnDestroy(struct UIWidget* pWidget)
{
    assert(pWidget->pImplementationData);
    free(pWidget->pImplementationData);
}

static void* OnOutputVerts(struct UIWidget* pWidget, VECTOR(WidgetVertex) pOutVerts)
{
    pOutVerts = UI_Helper_OnOutputVerts(pWidget, pOutVerts);
    return pOutVerts;
}

static void MakeWidgetIntoStackPanel(HWidget hWidget, struct DataNode* pNode)
{
    struct UIWidget* pWidget = UI_GetWidget(hWidget);
    pWidget->hNext = -1;
    pWidget->hPrev = -1;
    pWidget->hParent = -1;
    pWidget->hFirstChild = -1;
    pWidget->fnGetHeight = &GetHeight;
    pWidget->fnGetWidth = &GetWidth;
    pWidget->fnLayoutChildren = &LayoutChildren;
    pWidget->fnOnDestroy = &OnDestroy;
    pWidget->fnOutputVertices = &OnOutputVerts;
    pWidget->pImplementationData = malloc(sizeof(struct StackPanelWidgetData));
    memset(pWidget->pImplementationData, 0, sizeof(struct StackPanelWidgetData));
    struct StackPanelWidgetData* pData = pWidget->pImplementationData;
    StackPanel_PopulateDataFromXML(pNode, pData);
}

HWidget StackPanelWidgetNew(HWidget hParent, struct DataNode* pNode, struct XMLUIData* pUIData)
{
    HWidget hWidget = UI_NewBlankWidget();
    MakeWidgetIntoStackPanel(hWidget, pNode);
    return hWidget;
}