File TextButtonWidget.c

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

Go to the documentation of this file

#include "TextButtonWidget.h"
#include "Widget.h"
#include "XMLUIGameLayer.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "Atlas.h"
#include "AssertLib.h"
#include "TextWidget.h"
#include "BackgroundBoxWidget.h"
#include "RootWidget.h"
#include "Scripting.h"
#include "DataNode.h"

enum ButtonType
{
    BT_FireOnRelease,
    BT_FireOnDown
};

struct TextButtonWidgetData
{
    struct TextWidgetData textWidgetData;
    struct BackgroundBoxWidgetData backgroundBoxWidgetData;
    struct BackgroundBoxWidgetData pressedBackgroundBoxWidgetData;
    struct WidgetPadding textPadding;
    bool bPressed;
    HWidget RootWidget;
    enum ButtonType type;
    int viewmodelRegIndex;
    char onPressFunctionName[MAX_SCRIPT_FUNCTION_NAME_SIZE];
    bool bLuaCallbackSet;
};

static void MakeDefaultTextButtonWidgetData(struct TextButtonWidgetData* pData, struct XMLUIData* pUILayerData)
{
    pData->textPadding.paddingBottom = 20;
    pData->textPadding.paddingTop = 20;
    pData->textPadding.paddingLeft = 20;
    pData->textPadding.paddingRight = 20;
    const char* defaultBackgroundWidget = "defaultButton";
    const char* defaultPressedBackgroundWidget = "defaultPressedButton";

    // background widget

    pData->backgroundBoxWidgetData.atlas = pUILayerData->atlas;
    pData->pressedBackgroundBoxWidgetData.atlas = pUILayerData->atlas;

    pData->backgroundBoxWidgetData.scale.scaleX = 1.0f;
    pData->backgroundBoxWidgetData.scale.scaleY = 1.0f;

    pData->pressedBackgroundBoxWidgetData.scale.scaleX = 1.0f;
    pData->pressedBackgroundBoxWidgetData.scale.scaleY = 1.0f;

    pData->backgroundBoxWidgetData.imageName = malloc(strlen(defaultBackgroundWidget) + 1);
    strcpy(pData->backgroundBoxWidgetData.imageName, defaultBackgroundWidget);
    pData->backgroundBoxWidgetData.sprite = At_FindSprite(pData->backgroundBoxWidgetData.imageName, pData->backgroundBoxWidgetData.atlas);

    pData->pressedBackgroundBoxWidgetData.imageName = malloc(strlen(defaultPressedBackgroundWidget) + 1);
    strcpy(pData->pressedBackgroundBoxWidgetData.imageName, defaultPressedBackgroundWidget);
    pData->pressedBackgroundBoxWidgetData.sprite = At_FindSprite(pData->pressedBackgroundBoxWidgetData.imageName, pData->pressedBackgroundBoxWidgetData.atlas);


    // text widget
    pData->textWidgetData.atlas = pUILayerData->atlas;

    pData->textWidgetData.content = malloc(strlen("Button") + 1);
    strcpy(pData->textWidgetData.content, "Button");

    pData->textWidgetData.r = 0.0f;
    pData->textWidgetData.g = 0.0f;
    pData->textWidgetData.b = 0.0f;
    pData->textWidgetData.a = 1.0f;

    pData->textWidgetData.fSizePts = 32.0f;
    pData->textWidgetData.font = Fo_FindFont(pData->textWidgetData.atlas, "default", 32.0f);

    pData->bPressed = false;
}

static float GetWidth(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    struct TextWidgetData* pData = &pWD->textWidgetData;
    return Fo_StringWidth(pData->atlas, pData->font, pData->content) +
        pWD->textPadding.paddingLeft +
        pWD->textPadding.paddingRight +
        pWidget->padding.paddingLeft +
        pWidget->padding.paddingRight;
}

static float GetHeight(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    struct TextWidgetData* pData = &pWD->textWidgetData;
    return Fo_StringHeight(pData->atlas, pData->font, pData->content) +
        pWD->textPadding.paddingTop +
        pWD->textPadding.paddingBottom +
        pWidget->padding.paddingTop +
        pWidget->padding.paddingBottom;
}

static void LayoutChildren(struct UIWidget* pWidget, struct UIWidget* pParent)
{
    EASSERT(pWidget->hFirstChild == NULL_HWIDGET);
}

static void OnDestroy(struct UIWidget* pWidget)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    TextWidget_Destroy(&pWD->textWidgetData);
    BackgroundBoxWidget_Destroy(&pWD->pressedBackgroundBoxWidgetData);
    BackgroundBoxWidget_Destroy(&pWD->backgroundBoxWidgetData);
    free(pWidget->pImplementationData);
}

static void* OnOutputVerts(struct UIWidget* pWidget, VECTOR(WidgetVertex) pOutVerts)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    struct TextWidgetData* pTextWidgetData = &pWD->textWidgetData;
    struct BackgroundBoxWidgetData* pBBWD = pWD->bPressed ? &pWD->pressedBackgroundBoxWidgetData : &pWD->backgroundBoxWidgetData;
    pOutVerts = BackgroundBoxWidget_OutputVerts(
        pBBWD,
        pOutVerts,
        GetWidth(pWidget, NULL),
        GetHeight(pWidget, NULL),
        &pWidget->padding,
        pWidget->left,
        pWidget->top
    );
    pOutVerts = TextWidget_OutputVerts(pWidget->left + pWidget->padding.paddingLeft, pWidget->top + pWidget->padding.paddingTop, &pWD->textPadding, pTextWidgetData, pOutVerts);

    pOutVerts = UI_Helper_OnOutputVerts(pWidget, pOutVerts);
    return pOutVerts;
}


static void MouseButtonDownCallback(struct UIWidget* pWidget, float x, float y, int btn)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    pWD->bPressed = true;
    SetRootWidgetIsDirty(pWD->RootWidget, true);
    if (pWD->bLuaCallbackSet && pWD->type == BT_FireOnDown)
    {
        Sc_CallFuncInRegTableEntryTable(pWD->viewmodelRegIndex, pWD->onPressFunctionName, NULL, 0, 0);
    }
}

static void MouseButtonUpCallback(struct UIWidget* pWidget, float x, float y, int btn)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    pWD->bPressed = false;
    SetRootWidgetIsDirty(pWD->RootWidget, true);
    if (pWD->bLuaCallbackSet && pWD->type == BT_FireOnRelease)
    {
        Sc_CallFuncInRegTableEntryTable(pWD->viewmodelRegIndex, pWD->onPressFunctionName, NULL, 0, 0);
    }
}

static void MouseLeaveCallback(struct UIWidget* pWidget, float x, float y)
{
    struct TextButtonWidgetData* pWD = pWidget->pImplementationData;
    if (pWD->bPressed)
    {
        pWD->bPressed = false;
        SetRootWidgetIsDirty(pWD->RootWidget, true);
    }
}

static void SetCMouseCallbacks(struct UIWidget* pWidget)
{
    pWidget->cCallbacks.Callbacks[WC_OnMouseDown].type = WC_OnMouseDown;
    pWidget->cCallbacks.Callbacks[WC_OnMouseDown].callback.mouseBtnFn = &MouseButtonDownCallback;

    pWidget->cCallbacks.Callbacks[WC_OnMouseUp].type = WC_OnMouseUp;
    pWidget->cCallbacks.Callbacks[WC_OnMouseUp].callback.mouseBtnFn = &MouseButtonUpCallback;

    pWidget->cCallbacks.Callbacks[WC_OnMouseLeave].type = WC_OnMouseLeave;
    pWidget->cCallbacks.Callbacks[WC_OnMouseLeave].callback.mousePosFn = &MouseLeaveCallback;
}

static void MakeWidgetIntoTextButtonWidget(HWidget hWidget, struct DataNode* pDataNode, struct XMLUIData* pUILayerData)
{
    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 TextButtonWidgetData));
    memset(pWidget->pImplementationData, 0, sizeof(struct TextButtonWidgetData));
    struct TextButtonWidgetData* pData = pWidget->pImplementationData;
    pData->RootWidget = pUILayerData->rootWidget;
    pData->viewmodelRegIndex = pUILayerData->hViewModel;
    MakeDefaultTextButtonWidgetData(pData, pUILayerData);
    TextWidget_FromXML(pWidget, &pData->textWidgetData, pDataNode, pUILayerData);
    BackgroundBoxWidget_fromXML(pWidget, &pData->backgroundBoxWidgetData, pDataNode, pUILayerData);
    SetCMouseCallbacks(pWidget);

    if(pDataNode->fnGetPropType(pDataNode, "onPress") == DN_String)
    {
        size_t len = pDataNode->fnGetStrlen(pDataNode, "onPress");
        EASSERT(len < MAX_SCRIPT_FUNCTION_NAME_SIZE);
        pDataNode->fnGetStrcpy(pDataNode, "onPress", pData->onPressFunctionName);
        pData->bLuaCallbackSet = true;
    }
    if(pDataNode->fnGetPropType(pDataNode, "btnType") == DN_String)
    {
        if (pDataNode->fnStrCmp(pDataNode, "btnType", "OnRelease"))
        {
            pData->type = BT_FireOnRelease;
        }
        if (pDataNode->fnStrCmp(pDataNode, "btnType", "OnDown"))
        {
            pData->type = BT_FireOnDown;
        }
    }
}

HWidget TextButtonWidgetNew(HWidget hParent, struct DataNode* pDataNode, struct XMLUIData* pUILayerData)
{
    HWidget hWidget = UI_NewBlankWidget();
    MakeWidgetIntoTextButtonWidget(hWidget, pDataNode, pUILayerData);
    return hWidget;
}