#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdarg.h>
#include "menu.h"
#include "toolkit.h"
#include "../common/context.h"
#include "../ui/properties.h"
#include "../ui/window.h"
#include "container.h"
static UcxList *menus;
static UcxList *current;
void ui_menu(
char *label) {
ucx_list_free(current);
UiMenu *menu = malloc(
sizeof(UiMenu));
menu->item.add_to = (ui_menu_add_f)add_menu_widget;
menu->label = label;
menu->items =
NULL;
menu->parent =
NULL;
current = ucx_list_prepend(
NULL, menu);
menus = ucx_list_append(menus, menu);
}
void ui_submenu(
char *label) {
UiMenu *menu = malloc(
sizeof(UiMenu));
menu->item.add_to = (ui_menu_add_f)add_menu_widget;
menu->label = label;
menu->items =
NULL;
menu->parent =
NULL;
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, menu);
current = ucx_list_prepend(current, menu);
}
void ui_submenu_end() {
if(ucx_list_size(current) <
2) {
return;
}
current = ucx_list_remove(current, current);
}
void ui_menuitem(
char *label, ui_callback f,
void *userdata) {
ui_menuitem_gr(label, f, userdata, -
1);
}
void ui_menuitem_st(
char *stockid, ui_callback f,
void *userdata) {
ui_menuitem_stgr(stockid, f, userdata, -
1);
}
void ui_menuitem_gr(
char *label, ui_callback f,
void *userdata, ...) {
if(!current) {
return;
}
UiMenuItem *item = malloc(
sizeof(UiMenuItem));
item->item.add_to = (ui_menu_add_f)add_menuitem_widget;
item->label = label;
item->userdata = userdata;
item->callback = f;
item->groups =
NULL;
va_list ap;
va_start(ap, userdata);
int group;
while((group = va_arg(ap,
int)) != -
1) {
item->groups = ucx_list_append(item->groups, (
void*)(
intptr_t)group);
}
va_end(ap);
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
void ui_menuitem_stgr(
char *stockid, ui_callback f,
void *userdata, ...) {
if(!current) {
return;
}
UiStMenuItem *item = malloc(
sizeof(UiStMenuItem));
item->item.add_to = (ui_menu_add_f)add_menuitem_st_widget;
item->stockid = stockid;
item->userdata = userdata;
item->callback = f;
item->groups =
NULL;
va_list ap;
va_start(ap, userdata);
int group;
while((group = va_arg(ap,
int)) != -
1) {
item->groups = ucx_list_append(item->groups, (
void*)(
intptr_t)group);
}
va_end(ap);
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
void ui_menuseparator() {
if(!current) {
return;
}
UiMenuItemI *item = malloc(
sizeof(UiMenuItemI));
item->add_to = (ui_menu_add_f)add_menuseparator_widget;
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
void ui_checkitem(
char *label, ui_callback f,
void *userdata) {
if(!current) {
return;
}
UiCheckItem *item = malloc(
sizeof(UiCheckItem));
item->item.add_to = (ui_menu_add_f)add_checkitem_widget;
item->label = label;
item->callback = f;
item->userdata = userdata;
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
void ui_checkitem_nv(
char *label,
char *vname) {
if(!current) {
return;
}
UiCheckItemNV *item = malloc(
sizeof(UiCheckItemNV));
item->item.add_to = (ui_menu_add_f)add_checkitemnv_widget;
item->varname = vname;
item->label = label;
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
void ui_menuitem_list(UiList *items, ui_callback f,
void *userdata) {
if(!current) {
return;
}
UiMenuItemList *item = malloc(
sizeof(UiMenuItemList));
item->item.add_to = (ui_menu_add_f)add_menuitem_list_widget;
item->callback = f;
item->userdata = userdata;
item->list = items;
UiMenu *cm = current->data;
cm->items = ucx_list_append(cm->items, item);
}
GtkWidget *ui_create_menubar(UiObject *obj) {
if(menus ==
NULL) {
return NULL;
}
GtkWidget *mb = gtk_menu_bar_new();
UcxList *ls = menus;
while(ls) {
UiMenu *menu = ls->data;
menu->item.add_to(mb,
0, &menu->item, obj);
ls = ls->next;
}
return mb;
}
void add_menu_widget(GtkWidget *parent,
int i, UiMenuItemI *item, UiObject *obj) {
UiMenu *menu = (UiMenu*)item;
GtkWidget *menu_widget = gtk_menu_new();
GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label);
gtk_menu_item_set_submenu(
GTK_MENU_ITEM(menu_item), menu_widget);
UcxList *ls = menu->items;
int index =
0;
while(ls) {
UiMenuItemI *i = ls->data;
i->add_to(menu_widget, index, i, obj);
ls = ls->next;
index++;
}
gtk_menu_shell_append(
GTK_MENU_SHELL(parent), menu_item);
}
void add_menuitem_widget(GtkWidget *parent,
int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItem *i = (UiMenuItem*)item;
GtkWidget *widget = gtk_menu_item_new_with_mnemonic(i->label);
if(i->callback !=
NULL) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = i->userdata;
event->callback = i->callback;
event->value =
0;
g_signal_connect(
widget,
"activate",
G_CALLBACK(ui_menu_event_wrapper),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
gtk_menu_shell_append(
GTK_MENU_SHELL(parent), widget);
if(i->groups) {
uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
}
}
void add_menuitem_st_widget(
GtkWidget *parent,
int index,
UiMenuItemI *item,
UiObject *obj)
{
UiStMenuItem *i = (UiStMenuItem*)item;
GtkWidget *widget = gtk_image_menu_item_new_from_stock(i->stockid, obj->ctx->accel_group);
if(i->callback !=
NULL) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = i->userdata;
event->callback = i->callback;
event->value =
0;
g_signal_connect(
widget,
"activate",
G_CALLBACK(ui_menu_event_wrapper),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
gtk_menu_shell_append(
GTK_MENU_SHELL(parent), widget);
if(i->groups) {
uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
}
}
void add_menuseparator_widget(
GtkWidget *parent,
int index,
UiMenuItemI *item,
UiObject *obj)
{
gtk_menu_shell_append(
GTK_MENU_SHELL(parent),
gtk_separator_menu_item_new());
}
void add_checkitem_widget(GtkWidget *p,
int index, UiMenuItemI *item, UiObject *obj) {
UiCheckItem *ci = (UiCheckItem*)item;
GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
gtk_menu_shell_append(
GTK_MENU_SHELL(p), widget);
if(ci->callback) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = ci->userdata;
event->callback = ci->callback;
event->value =
0;
g_signal_connect(
widget,
"toggled",
G_CALLBACK(ui_menu_event_toggled),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
}
void add_checkitemnv_widget(GtkWidget *p,
int index, UiMenuItemI *item, UiObject *obj) {
UiCheckItemNV *ci = (UiCheckItemNV*)item;
GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
gtk_menu_shell_append(
GTK_MENU_SHELL(p), widget);
UiVar *var = uic_create_var(obj->ctx, ci->varname,
UI_VAR_INTEGER);
if(var) {
UiInteger *value = var->value;
value->obj = widget;
value->get = ui_checkitem_get;
value->set = ui_checkitem_set;
value =
0;
}
else {
}
}
void add_menuitem_list_widget(GtkWidget *p,
int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
UcxMempool *mp = obj->ctx->mempool;
UiActiveMenuItemList *ls = ucx_mempool_malloc(
mp,
sizeof(UiActiveMenuItemList));
ls->object = obj;
ls->menu =
GTK_MENU_SHELL(p);
ls->index = index;
ls->oldcount =
0;
ls->list = il->list;
ls->callback = il->callback;
ls->userdata = il->userdata;
ls->list->observers = ui_add_observer(
ls->list->observers,
(ui_callback)ui_update_menuitem_list,
ls);
ui_update_menuitem_list(
NULL, ls);
}
void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
if(list->oldcount >
0) {
int i =
0;
GList *mi = gtk_container_get_children(
GTK_CONTAINER(list->menu));
while(mi) {
if(i >= list->index && i < list->index + list->oldcount) {
gtk_widget_destroy(mi->data);
}
mi = mi->next;
i++;
}
}
char *str = ui_list_first(list->list);
if(str) {
GtkWidget *widget = gtk_separator_menu_item_new();
gtk_menu_shell_insert(list->menu, widget, list->index);
gtk_widget_show(widget);
}
int i =
1;
while(str) {
GtkWidget *widget = gtk_menu_item_new_with_label(str);
gtk_menu_shell_insert(list->menu, widget, list->index + i);
gtk_widget_show(widget);
if(list->callback) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = list->object;
event->userdata = list->userdata;
event->callback = list->callback;
event->value = i -
1;
g_signal_connect(
widget,
"activate",
G_CALLBACK(ui_menu_event_wrapper),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
str = ui_list_next(list->list);
i++;
}
list->oldcount = i;
}
void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) {
UiEvent evt;
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
evt.eventdata =
NULL;
evt.intval = event->value;
event->callback(&evt, event->userdata);
}
void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
UiEvent evt;
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
evt.eventdata =
NULL;
evt.intval = gtk_check_menu_item_get_active(ci);
event->callback(&evt, event->userdata);
}
int64_t ui_checkitem_get(UiInteger *i) {
int state = gtk_check_menu_item_get_active(i->obj);
i->value = state;
return state;
}
void ui_checkitem_set(UiInteger *i,
int64_t value) {
i->value = value;
gtk_check_menu_item_set_active(i->obj, value);
}
static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) {
if(event->type ==
GDK_BUTTON_PRESS) {
GdkEventButton *e = (GdkEventButton*)event;
if(e->button ==
3) {
gtk_widget_show_all(
GTK_WIDGET(menu));
ui_contextmenu_popup(menu);
return TRUE;
}
}
return FALSE;
}
UIMENU ui_contextmenu(UiObject *obj) {
UiContainer *ct = uic_get_current_container(obj);
return ui_contextmenu_w(obj, ct->current);
}
UIMENU ui_contextmenu_w(UiObject *obj,
UIWIDGET widget) {
UiContainer *ct = uic_get_current_container(obj);
GtkMenu *menu =
GTK_MENU(gtk_menu_new());
g_signal_connect(widget,
"button-press-event", (GCallback) ui_button_press_event, menu);
ct->menu = menu;
return menu;
}
void ui_contextmenu_popup(
UIMENU menu) {
#if GTK_MAJOR_VERSION >=
3 &&
GTK_MINOR_VERSION >=
16
gtk_menu_popup_at_pointer(menu,
NULL);
#else
gtk_menu_popup(menu,
NULL,
NULL,
0,
0,
0, gtk_get_current_event_time());
#endif
}
void ui_widget_menuitem(UiObject *obj,
char *label, ui_callback f,
void *userdata) {
ui_widget_menuitem_gr(obj, label, f, userdata, -
1);
}
void ui_widget_menuitem_gr(UiObject *obj,
char *label, ui_callback f,
void *userdata, ...) {
UiContainer *ct = uic_get_current_container(obj);
if(!ct->menu) {
return;
}
UcxList *groups =
NULL;
va_list ap;
va_start(ap, userdata);
int group;
while((group = va_arg(ap,
int)) != -
1) {
ucx_list_append(groups, (
void*)(
intptr_t)group);
}
va_end(ap);
GtkWidget *widget = gtk_menu_item_new_with_mnemonic(label);
gtk_widget_show(widget);
if(f) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = userdata;
event->callback = f;
event->value =
0;
g_signal_connect(
widget,
"activate",
G_CALLBACK(ui_menu_event_wrapper),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
gtk_menu_shell_append(
GTK_MENU_SHELL(ct->menu), widget);
if(groups) {
uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
}
}
void ui_widget_menuitem_st(UiObject *obj,
char *stockid, ui_callback f,
void *userdata) {
ui_widget_menuitem_stgr(obj, stockid, f, userdata, -
1);
}
void ui_widget_menuitem_stgr(UiObject *obj,
char *stockid, ui_callback f,
void *userdata, ...) {
UiContainer *ct = uic_get_current_container(obj);
if(!ct->menu) {
return;
}
UcxList *groups =
NULL;
va_list ap;
va_start(ap, userdata);
int group;
while((group = va_arg(ap,
int)) != -
1) {
ucx_list_append(groups, (
void*)(
intptr_t)group);
}
va_end(ap);
GtkWidget *widget = gtk_image_menu_item_new_from_stock(stockid, obj->ctx->accel_group);
gtk_widget_show(widget);
if(f) {
UiEventData *event = malloc(
sizeof(UiEventData));
event->obj = obj;
event->userdata = userdata;
event->callback = f;
event->value =
0;
g_signal_connect(
widget,
"activate",
G_CALLBACK(ui_menu_event_wrapper),
event);
g_signal_connect(
widget,
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
}
gtk_menu_shell_append(
GTK_MENU_SHELL(ct->menu), widget);
if(groups) {
uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups);
}
}