#include <stdio.h>
#include <stdlib.h>
#include "button.h"
#include "container.h"
#include <cx/allocator.h>
#include "../common/context.h"
#include "../common/object.h"
void ui_button_set_icon_name(GtkWidget *button,
const char *icon) {
if(!icon) {
return;
}
#ifdef UI_GTK4
gtk_button_set_icon_name(
GTK_BUTTON(button), icon);
#else
#if GTK_CHECK_VERSION(
2,
6,
0)
GtkWidget *image = gtk_image_new_from_icon_name(icon,
GTK_ICON_SIZE_BUTTON);
if(image) {
gtk_button_set_image(
GTK_BUTTON(button), image);
}
#else
#endif
#endif
}
GtkWidget* ui_create_button(
UiObject *obj,
const char *label,
const char *icon,
ui_callback onclick,
void *userdata,
int event_value,
bool activate_event)
{
GtkWidget *button = gtk_button_new_with_label(label);
ui_button_set_icon_name(button, icon);
if(onclick) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = userdata;
event->callback = onclick;
event->value = event_value;
event->customdata =
NULL;
g_signal_connect(
button,
"clicked",
G_CALLBACK(ui_button_clicked),
event);
g_signal_connect(
button,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
if(activate_event) {
g_signal_connect(
button,
"activate",
G_CALLBACK(ui_button_clicked),
event);
}
}
return button;
}
UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata,
0,
FALSE);
ui_set_name_and_style(button, args.name, args.style_class);
ui_set_widget_groups(obj->ctx, button, args.groups);
UI_APPLY_LAYOUT1(current, args);
current->container->add(current->container, button,
FALSE);
return button;
}
void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata =
NULL;
e.intval = event->value;
event->callback(&e, event->userdata);
}
int64_t ui_toggle_button_get(UiInteger *integer) {
GtkToggleButton *button = integer->obj;
integer->value = (
int)gtk_toggle_button_get_active(button);
return integer->value;
}
void ui_toggle_button_set(UiInteger *integer,
int64_t value) {
GtkToggleButton *button = integer->obj;
integer->value = value;
gtk_toggle_button_set_active(button, value !=
0 ?
TRUE :
FALSE);
}
void ui_toggled_obs(
void *widget, UiVarEventData *event) {
UiInteger *i = event->var->value;
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = event->var->value;
e.intval = i->get(i);
ui_notify_evt(i->observers, &e);
}
static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) {
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata =
NULL;
e.intval = gtk_toggle_button_get_active(widget);
event->callback(&e, event->userdata);
}
static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) {
if(gtk_toggle_button_get_active(widget)) {
ui_set_group(event->obj->ctx, event->value);
}
else {
ui_unset_group(event->obj->ctx, event->value);
}
}
void ui_setup_togglebutton(
UiObject *obj,
GtkWidget *togglebutton,
const char *label,
const char *icon,
const char *varname,
UiInteger *value,
ui_callback onchange,
void *onchangedata,
int enable_state)
{
if(label) {
gtk_button_set_label(
GTK_BUTTON(togglebutton), label);
}
ui_button_set_icon_name(togglebutton, icon);
ui_bind_togglebutton(
obj,
togglebutton,
ui_toggle_button_get,
ui_toggle_button_set,
varname,
value,
(ui_toggled_func)ui_toggled_callback,
onchange,
onchangedata,
(ui_toggled_func)ui_togglebutton_enable_state_callback,
enable_state
);
}
void ui_bind_togglebutton(
UiObject *obj,
GtkWidget *widget,
int64_t (*getfunc)(UiInteger*),
void (*setfunc)(UiInteger*,
int64_t),
const char *varname,
UiInteger *value,
void (*toggled_callback)(
void*,
void*),
ui_callback onchange,
void *onchangedata,
void (*enable_state_func)(
void*,
void*),
int enable_state)
{
UiObject* current = uic_current_obj(obj);
UiVar* var = uic_widget_var(obj->ctx, current->ctx, value, varname,
UI_VAR_INTEGER);
if (var) {
UiInteger* value = (UiInteger*)var->value;
value->obj = widget;
value->get = getfunc;
value->set = setfunc;
UiVarEventData *event = malloc(
sizeof(UiVarEventData));
event->obj = obj;
event->var = var;
event->observers =
NULL;
event->callback =
NULL;
event->userdata =
NULL;
g_signal_connect(
widget,
"toggled",
G_CALLBACK(ui_toggled_obs),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_vardata),
event);
}
if(onchange) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = onchangedata;
event->callback = onchange;
event->value =
0;
event->customdata =
NULL;
g_signal_connect(
widget,
"toggled",
G_CALLBACK(toggled_callback),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
if(enable_state >
0) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata =
NULL;
event->callback =
NULL;
event->value = enable_state;
event->customdata =
NULL;
g_signal_connect(
widget,
"toggled",
G_CALLBACK(enable_state_func),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
}
static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs args) {
UiObject* current = uic_current_obj(obj);
ui_setup_togglebutton(
current,
widget,
args.label,
args.icon,
args.varname,
args.value,
args.onchange,
args.onchangedata,
args.enable_group);
ui_set_name_and_style(widget, args.name, args.style_class);
ui_set_widget_groups(obj->ctx, widget, args.groups);
UI_APPLY_LAYOUT1(current, args);
current->container->add(current->container, widget,
FALSE);
return widget;
}
UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) {
return togglebutton_create(obj, gtk_toggle_button_new(), args);
}
#if GTK_MAJOR_VERSION >=
4
int64_t ui_check_button_get(UiInteger *integer) {
GtkCheckButton *button = integer->obj;
integer->value = (
int)gtk_check_button_get_active(button);
return integer->value;
}
void ui_check_button_set(UiInteger *integer,
int64_t value) {
GtkCheckButton *button = integer->obj;
integer->value = value;
gtk_check_button_set_active(button, value !=
0 ?
TRUE :
FALSE);
}
static void ui_checkbox_callback(GtkCheckButton *widget, UiEventData *event) {
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata =
NULL;
e.intval = gtk_check_button_get_active(widget);
event->callback(&e, event->userdata);
}
static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event) {
if(gtk_check_button_get_active(widget)) {
ui_set_group(event->obj->ctx, event->value);
}
else {
ui_unset_group(event->obj->ctx, event->value);
}
}
UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
UiObject* current = uic_current_obj(obj);
GtkWidget *widget = gtk_check_button_new_with_label(args.label);
ui_bind_togglebutton(
obj,
widget,
ui_check_button_get,
ui_check_button_set,
args.varname,
args.value,
(ui_toggled_func)ui_checkbox_callback,
args.onchange,
args.onchangedata,
(ui_toggled_func)ui_checkbox_enable_state,
args.enable_group);
ui_set_name_and_style(widget, args.name, args.style_class);
ui_set_widget_groups(obj->ctx, widget, args.groups);
UI_APPLY_LAYOUT1(current, args);
current->container->add(current->container, widget,
FALSE);
return widget;
}
#else
UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) {
return togglebutton_create(obj, gtk_check_button_new(), args);
}
#endif
UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) {
#ifdef UI_GTK3
return NULL;
#else
return ui_checkbox_create(obj, args);
#endif
}
#if GTK_MAJOR_VERSION >=
4
#define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label)
#define RADIOBUTTON_SET_GROUP(button, group)
#define RADIOBUTTON_GET_GROUP(button)
GTK_CHECK_BUTTON(button)
#define RADIOBUTTON_GET_ACTIVE(button) gtk_check_button_get_active(
GTK_CHECK_BUTTON(button))
#else
#define RADIOBUTTON_NEW(group, label) gtk_radio_button_new_with_label(group, label)
#define RADIOBUTTON_SET_GROUP(button, group)
#define RADIOBUTTON_GET_GROUP(button) gtk_radio_button_get_group(
GTK_RADIO_BUTTON(button))
#define RADIOBUTTON_GET_ACTIVE(button) gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(button))
#endif
static void radiobutton_toggled(
void *widget, UiEventData *event) {
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata =
NULL;
e.intval =
RADIOBUTTON_GET_ACTIVE(widget);
event->callback(&e, event->userdata);
}
typedef struct UiRadioButtonData {
UiInteger *value;
UiVarEventData *eventdata;
UiBool first;
} UiRadioButtonData;
static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) {
if(data->first) {
ui_destroy_vardata(w, data->eventdata);
g_slist_free(data->value->obj);
data->value->obj =
NULL;
data->value->get =
NULL;
data->value->set =
NULL;
}
else {
free(data->eventdata);
}
free(data);
}
UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs args) {
UiObject* current = uic_current_obj(obj);
GSList *rg =
NULL;
UiInteger *rgroup;
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_INTEGER);
UiBool first =
FALSE;
if(var) {
rgroup = var->value;
rg = rgroup->obj;
if(!rg) {
first =
TRUE;
}
}
GtkWidget *rbutton =
RADIOBUTTON_NEW(rg, args.label);
ui_set_name_and_style(rbutton, args.name, args.style_class);
ui_set_widget_groups(obj->ctx, rbutton, args.groups);
if(rgroup) {
#if GTK_MAJOR_VERSION >=
4
if(rg) {
gtk_check_button_set_group(
GTK_CHECK_BUTTON(rbutton), rg->data);
}
rg = g_slist_prepend(rg, rbutton);
#else
gtk_radio_button_set_group(
GTK_RADIO_BUTTON(rbutton), rg);
rg = gtk_radio_button_get_group(
GTK_RADIO_BUTTON(rbutton));
#endif
rgroup->obj = rg;
rgroup->get = ui_radiobutton_get;
rgroup->set = ui_radiobutton_set;
ui_radiobutton_set(rgroup, rgroup->value);
UiVarEventData *event = malloc(
sizeof(UiVarEventData));
event->obj = obj;
event->var = var;
event->observers =
NULL;
event->callback =
NULL;
event->userdata =
NULL;
UiRadioButtonData *rbdata = malloc(
sizeof(UiRadioButtonData));
rbdata->value = rgroup;
rbdata->eventdata = event;
rbdata->first = first;
g_signal_connect(
rbutton,
"toggled",
G_CALLBACK(ui_radio_obs),
event);
g_signal_connect(
rbutton,
"destroy",
G_CALLBACK(destroy_radiobutton),
rbdata);
}
if(args.onchange) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = args.onchangedata;
event->callback = args.onchange;
event->value =
0;
event->customdata =
NULL;
g_signal_connect(
rbutton,
"toggled",
G_CALLBACK(radiobutton_toggled),
event);
g_signal_connect(
rbutton,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
UI_APPLY_LAYOUT1(current, args);
current->container->add(current->container, rbutton,
FALSE);
return rbutton;
}
void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) {
UiInteger *i = event->var->value;
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata =
NULL;
e.intval = i->get(i);
ui_notify_evt(i->observers, &e);
}
#if GTK_MAJOR_VERSION >=
4
int64_t ui_radiobutton_get(UiInteger *value) {
int selection =
0;
GSList *ls = value->obj;
int i =
0;
guint len = g_slist_length(ls);
while(ls) {
if(gtk_check_button_get_active(
GTK_CHECK_BUTTON(ls->data))) {
selection = len - i -
1;
break;
}
ls = ls->next;
i++;
}
value->value = selection;
return selection;
}
void ui_radiobutton_set(UiInteger *value,
int64_t i) {
GSList *ls = value->obj;
int s = g_slist_length(ls) -
1 - i;
int j =
0;
while(ls) {
if(j == s) {
gtk_check_button_set_active(
GTK_CHECK_BUTTON(ls->data),
TRUE);
break;
}
ls = ls->next;
j++;
}
value->value = i;
}
#else
int64_t ui_radiobutton_get(UiInteger *value) {
int selection =
0;
GSList *ls = value->obj;
int i =
0;
guint len = g_slist_length(ls);
while(ls) {
if(gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(ls->data))) {
selection = len - i -
1;
break;
}
ls = ls->next;
i++;
}
value->value = selection;
return selection;
}
void ui_radiobutton_set(UiInteger *value,
int64_t i) {
GSList *ls = value->obj;
int s = g_slist_length(ls) -
1 - i;
int j =
0;
while(ls) {
if(j == s) {
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(ls->data),
TRUE);
break;
}
ls = ls->next;
j++;
}
value->value = i;
}
#endif