#include "button.h"
#include "button.inl"
#include "component.inl"
#include "cell.inl"
#include "gui.inl"
#include "gbind.inl"
#include "panel.inl"
#include <draw2d/font.h>
#include <draw2d/guictx.h>
#include <draw2d/image.h>
#include <geom2d/s2d.h>
#include <geom2d/v2d.h>
#include <core/event.h>
#include <core/objh.h>
#include <core/strings.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
struct _button_t
{
GuiComponent component;
uint32_t flags;
real32_t min_width;
S2Df size;
Font *font;
ResId textid;
ResId taltid;
ResId ttipid;
String *text;
String *talt;
Image *image;
Image *imalt;
Listener *OnClick;
};
void _button_destroy(Button **button)
{
cassert_no_null(button);
cassert_no_null(*button);
_component_destroy_imp(&(*button)->component);
listener_destroy(&(*button)->OnClick);
str_destroy(&(*button)->text);
ptr_destopt(font_destroy, &(*button)->font, Font);
ptr_destopt(str_destroy, &(*button)->talt, String);
ptr_destopt(image_destroy, &(*button)->image, Image);
ptr_destopt(image_destroy, &(*button)->imalt, Image);
obj_delete(button, Button);
}
static ___INLINE void i_update_button(Button *button, const gui_state_t state)
{
cassert_no_null(button);
if (button_get_type(button->flags) == ekBUTTON_FLATGLE)
{
if (button->talt != NULL)
{
if (state == ekGUI_ON)
{
button->component.context->func_set_tooltip[ekGUI_TYPE_BUTTON](button->component.ositem, tc(button->talt));
}
else
{
cassert(state == ekGUI_OFF);
button->component.context->func_set_tooltip[ekGUI_TYPE_BUTTON](button->component.ositem, tc(button->text));
}
}
if (button->imalt != NULL)
{
if (state == ekGUI_ON)
{
button->component.context->func_button_set_image(button->component.ositem, button->imalt);
}
else
{
cassert(state == ekGUI_OFF);
button->component.context->func_button_set_image(button->component.ositem, button->image);
}
}
}
else if (button_get_type(button->flags) == ekBUTTON_RADIO)
{
Cell *cell = _component_cell(&button->component);
if (cell != NULL)
_cell_set_radio(cell);
}
}
static void i_OnClick(Button *button, Event *event)
{
EvButton *params = NULL;
Button *sender = button;
cassert_no_null(button);
cassert(button->component.ositem == event_sender_imp(event, NULL));
cassert_no_null(event);
cassert(event_type(event) == ekGUI_EVENT_BUTTON);
params = event_params(event, EvButton);
cassert_no_null(params);
cassert(params->index == 0);
i_update_button(button, params->state);
switch (button_get_type(button->flags))
{
case ekBUTTON_RADIO:
{
Cell *ccell = _component_cell(&button->component);
if (ccell != NULL)
{
Cell *cell = _cell_radio_dbind_cell(ccell);
params->index = _cell_radio_index(ccell);
if (cell != NULL)
_cell_update_u32(cell, params->index);
if (button->OnClick == NULL)
sender = _cell_radio_listener(ccell);
}
break;
}
case ekBUTTON_CHECK2:
case ekBUTTON_FLATGLE:
{
Cell *cell = _component_cell(&button->component);
if (cell != NULL)
_cell_update_bool(cell, params->state == ekGUI_OFF ? FALSE : TRUE);
break;
}
case ekBUTTON_CHECK3:
{
Cell *cell = _component_cell(&button->component);
if (cell != NULL)
{
uint32_t v = 0;
switch (params->state)
{
case ekGUI_OFF:
v = 0;
break;
case ekGUI_ON:
v = 1;
break;
case ekGUI_MIXED:
v = 2;
break;
cassert_default();
}
_cell_update_u32(cell, v);
}
break;
}
}
if (sender && sender->OnClick)
{
cassert(params->text == NULL);
if (button_get_type(button->flags) == ekBUTTON_FLATGLE && params->state == ekGUI_ON && button->talt != NULL)
params->text = tc(button->talt);
else
params->text = tc(button->text);
listener_pass_event(sender->OnClick, event, sender, Button);
}
}
static Button *i_create(const uint32_t flags, const align_t halign)
{
const GuiCtx *context = guictx_get_current();
Button *button = obj_new0(Button);
void *ositem = context->func_create[ekGUI_TYPE_BUTTON](flags);
_component_init(&button->component, context, PARAM(type, ekGUI_TYPE_BUTTON), &ositem);
button->flags = flags;
button->text = str_c("");
button->min_width = 0;
if (button_get_type(flags) != ekBUTTON_FLAT && button_get_type(flags) != ekBUTTON_FLATGLE)
{
button->font = _gui_create_default_font();
context->func_button_set_align(button->component.ositem, (enum_t)halign);
context->func_button_set_font(button->component.ositem, button->font);
}
context->func_button_OnClick(button->component.ositem, obj_listener(button, i_OnClick, Button));
return button;
}
Button *button_push(void)
{
return i_create(ekBUTTON_PUSH, ekCENTER);
}
Button *button_check(void)
{
return i_create(ekBUTTON_CHECK2, ekLEFT);
}
Button *button_check3(void)
{
return i_create(ekBUTTON_CHECK3, ekLEFT);
}
Button *button_radio(void)
{
return i_create(ekBUTTON_RADIO, ekLEFT);
}
Button *button_flat(void)
{
return i_create(ekBUTTON_FLAT, ekLEFT);
}
Button *button_flatgle(void)
{
return i_create(ekBUTTON_FLATGLE, ekCENTER);
}
void button_OnClick(Button *button, Listener *listener)
{
cassert_no_null(button);
listener_update(&button->OnClick, listener);
}
void button_min_width(Button *button, const real32_t width)
{
cassert_no_null(button);
cassert(width > 0);
button->min_width = width;
}
static void i_update_text(Button *button)
{
switch (button_get_type(button->flags))
{
case ekBUTTON_PUSH:
case ekBUTTON_CHECK2:
case ekBUTTON_CHECK3:
case ekBUTTON_RADIO:
button->component.context->func_button_set_text(button->component.ositem, tc(button->text));
break;
case ekBUTTON_FLAT:
case ekBUTTON_FLATGLE:
button->component.context->func_set_tooltip[ekGUI_TYPE_BUTTON](button->component.ositem, tc(button->text));
break;
cassert_default();
}
}
void button_text(Button *button, const char_t *text)
{
const char_t *ltext;
cassert_no_null(button);
ltext = _gui_respack_text(text, &button->textid);
str_upd(&button->text, ltext);
i_update_text(button);
}
void button_text_alt(Button *button, const char_t *text)
{
const char_t *ltext;
cassert_no_null(button);
cassert(button_get_type(button->flags) == ekBUTTON_FLATGLE);
ltext = _gui_respack_text(text, &button->taltid);
str_upd(&button->talt, ltext);
}
void button_tooltip(Button *button, const char_t *text)
{
const char_t *ltext = NULL;
cassert_no_null(button);
if (text != NULL)
ltext = _gui_respack_text(text, &button->ttipid);
button->component.context->func_set_tooltip[ekGUI_TYPE_BUTTON](button->component.ositem, ltext);
}
void button_font(Button *button, const Font *font)
{
cassert_no_null(button);
if (_gui_update_font(&button->font, NULL, font) == TRUE)
button->component.context->func_button_set_font(button->component.ositem, button->font);
}
const Font *button_get_font(const Button *button)
{
cassert_no_null(button);
return button->font;
}
void button_image(Button *button, const Image *image)
{
const Image *limage = _gui_respack_image((ResId)image, NULL);
cassert_no_null(button);
cassert(button_get_type(button->flags) == ekBUTTON_PUSH || button_get_type(button->flags) == ekBUTTON_FLAT || button_get_type(button->flags) == ekBUTTON_FLATGLE);
ptr_destopt(image_destroy, &button->image, Image);
button->image = ptr_copyopt(image_copy, limage, Image);
button->component.context->func_button_set_image(button->component.ositem, limage);
}
void button_image_alt(Button *button, const Image *image)
{
const Image *limage = _gui_respack_image((ResId)image, NULL);
cassert_no_null(button);
cassert(button_get_type(button->flags) == ekBUTTON_FLATGLE);
ptr_destopt(image_destroy, &button->imalt, Image);
button->imalt = ptr_copyopt(image_copy, limage, Image);
}
void button_state(Button *button, const gui_state_t state)
{
cassert_no_null(button);
if (button_get_type(button->flags) != ekBUTTON_RADIO)
{
button->component.context->func_button_set_state(button->component.ositem, (enum_t)state);
}
else
{
if (state == ekGUI_ON)
{
Cell *cell = _component_cell(&button->component);
button->component.context->func_button_set_state(button->component.ositem, (enum_t)state);
if (cell != NULL)
_cell_set_radio(cell);
}
}
}
void button_tag(Button *button, const uint32_t tag)
{
cassert_no_null(button);
_component_set_tag(&button->component, tag);
}
void button_vpadding(Button *button, const real32_t padding)
{
cassert_no_null(button);
cassert_no_nullf(button->component.context->func_button_set_vpadding);
button->component.context->func_button_set_vpadding(button->component.ositem, padding);
}
gui_state_t button_get_state(const Button *button)
{
cassert_no_null(button);
return (gui_state_t)button->component.context->func_button_get_state(button->component.ositem);
}
uint32_t button_get_tag(const Button *button)
{
cassert_no_null(button);
return _component_get_tag(&button->component);
}
real32_t button_get_height(const Button *button)
{
real32_t width, height;
cassert_no_null(button);
_button_natural(cast(button, Button), 0, &width, &height);
_button_natural(cast(button, Button), 1, &width, &height);
return height;
}
void _button_natural(Button *button, const uint32_t i, real32_t *dim0, real32_t *dim1)
{
cassert_no_null(button);
cassert_no_null(dim0);
cassert_no_null(dim1);
if (i == 0)
{
if (button_get_type(button->flags) != ekBUTTON_FLAT && button_get_type(button->flags) != ekBUTTON_FLATGLE)
{
real32_t width = -1, height = -1;
if (button->image != NULL)
{
width = (real32_t)image_width(button->image);
height = (real32_t)image_height(button->image);
}
button->component.context->func_button_bounds(button->component.ositem, tc(button->text), width, height, &button->size.width, &button->size.height);
if (button_get_type(button->flags) == ekBUTTON_PUSH)
{
if (button->size.width < button->min_width)
button->size.width = button->min_width;
}
}
else
{
real32_t width = (real32_t)image_width(button->image);
real32_t height = (real32_t)image_height(button->image);
button->component.context->func_button_bounds(button->component.ositem, NULL, width, height, &button->size.width, &button->size.height);
}
*dim0 = button->size.width;
}
else
{
cassert(i == 1);
*dim1 = button->size.height;
}
}
void _button_locale(Button *button)
{
cassert_no_null(button);
if (button->textid != NULL)
{
const char_t *text = _gui_respack_text(button->textid, NULL);
str_upd(&button->text, text);
}
if (button->taltid != NULL)
{
const char_t *text = _gui_respack_text(button->taltid, NULL);
str_upd(&button->talt, text);
}
i_update_text(button);
if (button->ttipid != NULL)
{
const char_t *text = _gui_respack_text(button->ttipid, NULL);
button->component.context->func_set_tooltip[ekGUI_TYPE_BUTTON](button->component.ositem, text);
}
}
uint32_t _button_flags(const Button *button)
{
cassert_no_null(button);
return button->flags;
}
bool_t _button_is_pushbutton(const Button *button)
{
cassert_no_null(button);
return (bool_t)(button_get_type(button->flags) == ekBUTTON_PUSH);
}
bool_t _button_is_radio(const Button *button)
{
cassert_no_null(button);
return (bool_t)(button_get_type(button->flags) == ekBUTTON_RADIO);
}
Listener *_button_radio_listener(const Button *button)
{
cassert_no_null(button);
if (button_get_type(button->flags) == ekBUTTON_RADIO)
return button->OnClick;
return NULL;
}
void _button_radio_state(Button *button, const gui_state_t state)
{
cassert_no_null(button);
cassert(button_get_type(button->flags) == ekBUTTON_RADIO);
button->component.context->func_button_set_state(button->component.ositem, (enum_t)state);
}
void _button_bool(Button *button, const bool_t value)
{
_button_uint32(button, (uint32_t)value);
}
void _button_uint32(Button *button, const uint32_t value)
{
cassert_no_null(button);
switch (button_get_type(button->flags))
{
case ekBUTTON_RADIO:
{
Cell *cell = _component_cell(&button->component);
if (cell != NULL)
_cell_set_radio_index(cell, value);
break;
}
case ekBUTTON_FLATGLE:
case ekBUTTON_CHECK2:
button_state(button, value == 0 ? ekGUI_OFF : ekGUI_ON);
break;
case ekBUTTON_CHECK3:
{
gui_state_t st = ekGUI_MIXED;
if (value == 0)
st = ekGUI_OFF;
else if (value == 1)
st = ekGUI_ON;
button_state(button, st);
break;
}
cassert_default();
}
}