gui/lvgl/src/widgets/msgbox/lv_msgbox.c
/**
 * @file lv_msgbox.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_msgbox_private.h"
#include "../../core/lv_obj_private.h"
#include "../../core/lv_obj_class_private.h"
#if LV_USE_MSGBOX

#include "../label/lv_label.h"
#include "../button/lv_button.h"
#include "../image/lv_image.h"
#include "../../misc/lv_assert.h"
#include "../../display/lv_display.h"
#include "../../layouts/flex/lv_flex.h"
#include "../../stdlib/lv_string.h"

/*********************
 *      DEFINES
 *********************/
#define LV_MSGBOX_FLAG_AUTO_PARENT  LV_OBJ_FLAG_WIDGET_1        /*Mark that the parent was automatically created*/
#define MY_CLASS (&lv_msgbox_class)

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void msgbox_close_click_event_cb(lv_event_t * e);
static void msgbox_size_changed_event_cb(lv_event_t * e);

/**********************
 *  STATIC VARIABLES
 **********************/
const lv_obj_class_t lv_msgbox_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_DPI_DEF * 2,
    .height_def = LV_SIZE_CONTENT,
    .instance_size = sizeof(lv_msgbox_t),
    .name = "msgbox",
};

const lv_obj_class_t lv_msgbox_header_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_PCT(100),
    .height_def = LV_DPI_DEF / 3,
    .instance_size = sizeof(lv_obj_t),
    .name = "msgbox-header",
};

const lv_obj_class_t lv_msgbox_content_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_PCT(100),
    .height_def = LV_SIZE_CONTENT,
    .instance_size = sizeof(lv_obj_t),
    .name = "msgbox-content",
};

const lv_obj_class_t lv_msgbox_footer_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_PCT(100),
    .height_def = LV_DPI_DEF / 3,
    .instance_size = sizeof(lv_obj_t),
    .name = "msgbox-footer",
};

const lv_obj_class_t lv_msgbox_footer_button_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_SIZE_CONTENT,
    .height_def = LV_PCT(100),
    .instance_size = sizeof(lv_obj_t),
    .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
    .name = "msgbox-footer-button",
};

const lv_obj_class_t lv_msgbox_header_button_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_DPI_DEF / 3,
    .height_def = LV_PCT(100),
    .instance_size = sizeof(lv_obj_t),
    .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
    .name = "msgbox-header-button",
};

const lv_obj_class_t lv_msgbox_backdrop_class = {
    .base_class = &lv_obj_class,
    .width_def = LV_PCT(100),
    .height_def = LV_PCT(100),
    .instance_size = sizeof(lv_obj_t),
    .name = "msgbox-backdrop",
};

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

lv_obj_t * lv_msgbox_create(lv_obj_t * parent)
{
    LV_LOG_INFO("begin");
    bool auto_parent = false;
    if(parent == NULL) {
        auto_parent = true;
        parent = lv_obj_class_create_obj(&lv_msgbox_backdrop_class, lv_layer_top());
        LV_ASSERT_MALLOC(parent);
        lv_obj_class_init_obj(parent);
        lv_obj_remove_flag(parent, LV_OBJ_FLAG_IGNORE_LAYOUT);
        lv_obj_set_size(parent, LV_PCT(100), LV_PCT(100));
    }

    lv_obj_t * obj = lv_obj_class_create_obj(&lv_msgbox_class, parent);
    LV_ASSERT_MALLOC(obj);
    if(obj == NULL) return NULL;
    lv_obj_class_init_obj(obj);
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);

    if(auto_parent) lv_obj_add_flag(obj, LV_MSGBOX_FLAG_AUTO_PARENT);

    mbox->content = lv_obj_class_create_obj(&lv_msgbox_content_class, obj);
    LV_ASSERT_MALLOC(obj);
    if(mbox->content == NULL) return NULL;
    lv_obj_class_init_obj(mbox->content);
    lv_obj_set_flex_flow(mbox->content, LV_FLEX_FLOW_COLUMN);
    lv_obj_add_event_cb(obj, msgbox_size_changed_event_cb, LV_EVENT_SIZE_CHANGED, 0);

    lv_obj_center(obj);
    return obj;
}

lv_obj_t * lv_msgbox_add_title(lv_obj_t * obj, const char * title)
{
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    if(mbox->header == NULL) {
        mbox->header = lv_obj_class_create_obj(&lv_msgbox_header_class, obj);
        LV_ASSERT_MALLOC(obj);
        if(mbox->header == NULL) return NULL;
        lv_obj_class_init_obj(mbox->header);

        lv_obj_set_size(mbox->header, lv_pct(100), lv_display_get_dpi(lv_obj_get_display(obj)) / 3);
        lv_obj_set_flex_flow(mbox->header, LV_FLEX_FLOW_ROW);
        lv_obj_set_flex_align(mbox->header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
        lv_obj_remove_flag(mbox->header, LV_OBJ_FLAG_SCROLLABLE);
        lv_obj_move_to_index(mbox->header, 0);
    }

    if(mbox->title == NULL) {
        mbox->title = lv_label_create(mbox->header);
        lv_obj_set_flex_grow(mbox->title, 1);
    }

    lv_label_set_text(mbox->title, title);

    return mbox->title;
}

lv_obj_t * lv_msgbox_add_header_button(lv_obj_t * obj, const void * icon)
{
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    if(mbox->header == NULL) {
        lv_msgbox_add_title(obj, ""); /*Just to push the buttons to the right*/
    }

    lv_obj_t * btn = lv_obj_class_create_obj(&lv_msgbox_header_button_class, mbox->header);
    LV_ASSERT_MALLOC(obj);
    if(btn == NULL) return NULL;
    lv_obj_class_init_obj(btn);
    lv_obj_remove_flag(btn, LV_OBJ_FLAG_SCROLLABLE);

    if(icon) {
        lv_obj_t * img = lv_image_create(btn);
        lv_image_set_src(img, icon);
        lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);
    }

    return btn;
}

lv_obj_t * lv_msgbox_add_text(lv_obj_t * obj, const char * text)
{
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;

    lv_obj_t * label = lv_label_create(mbox->content);
    lv_label_set_text(label, text);
    lv_obj_set_width(label, lv_pct(100));

    return label;
}

lv_obj_t * lv_msgbox_add_footer_button(lv_obj_t * obj, const char * text)
{
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    if(mbox->footer == NULL) {
        mbox->footer = lv_obj_class_create_obj(&lv_msgbox_footer_class, obj);
        LV_ASSERT_MALLOC(obj);
        if(mbox->footer == NULL) return NULL;
        lv_obj_class_init_obj(mbox->footer);

        lv_obj_set_flex_flow(mbox->footer, LV_FLEX_FLOW_ROW);
        lv_obj_set_flex_align(mbox->footer, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
        lv_obj_remove_flag(mbox->footer, LV_OBJ_FLAG_SCROLLABLE);
    }

    lv_obj_t * btn = lv_obj_class_create_obj(&lv_msgbox_footer_button_class, mbox->footer);
    LV_ASSERT_MALLOC(obj);
    if(btn == NULL) return NULL;
    lv_obj_class_init_obj(btn);
    lv_obj_remove_flag(btn, LV_OBJ_FLAG_SCROLLABLE);

    if(text) {
        lv_obj_t * label = lv_label_create(btn);
        lv_label_set_text(label, text);
        lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
    }

    return btn;
}

lv_obj_t * lv_msgbox_add_close_button(lv_obj_t * obj)
{
    lv_obj_t * btn = lv_msgbox_add_header_button(obj, LV_SYMBOL_CLOSE);
    lv_obj_add_event_cb(btn, msgbox_close_click_event_cb, LV_EVENT_CLICKED, NULL);
    return btn;
}

lv_obj_t * lv_msgbox_get_header(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    return mbox->header;
}

lv_obj_t * lv_msgbox_get_footer(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    return mbox->footer;
}

lv_obj_t * lv_msgbox_get_content(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    return mbox->content;
}

lv_obj_t * lv_msgbox_get_title(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
    return mbox->title;
}

void lv_msgbox_close(lv_obj_t * obj)
{
    if(lv_obj_has_flag(obj, LV_MSGBOX_FLAG_AUTO_PARENT)) lv_obj_delete(lv_obj_get_parent(obj));
    else lv_obj_delete(obj);
}

void lv_msgbox_close_async(lv_obj_t * obj)
{
    if(lv_obj_has_flag(obj, LV_MSGBOX_FLAG_AUTO_PARENT)) lv_obj_delete_async(lv_obj_get_parent(obj));
    else lv_obj_delete_async(obj);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void msgbox_close_click_event_cb(lv_event_t * e)
{
    lv_obj_t * btn = lv_event_get_current_target(e);
    lv_obj_t * mbox = lv_obj_get_parent(lv_obj_get_parent(btn));
    lv_msgbox_close(mbox);
}

static void msgbox_size_changed_event_cb(lv_event_t * e)
{
    lv_obj_t * mbox = lv_event_get_target(e);
    lv_obj_t * content = lv_msgbox_get_content(mbox);
    bool is_msgbox_height_size_content = (lv_obj_get_style_height(mbox, 0) == LV_SIZE_CONTENT);
    lv_obj_set_flex_grow(content, !is_msgbox_height_size_content);
}

#endif /*LV_USE_MSGBOX*/
