/* Calf Box, an open source musical instrument. Copyright (C) 2010-2011 Krzysztof Foltman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "menu.h" #if USE_NCURSES #include "menuitem.h" #include #include /*******************************************************************/ static void item_measure(struct cbox_menu_item *item, struct cbox_menu_state *state) { struct cbox_menu_measure *m = &state->size; gchar *value = item->item_class->format_value(item, state); int len = strlen(item->label); int len2 = value ? strlen(value) : 0; if (len > m->label_width) m->label_width = len; if (len2 > m->value_width) m->value_width = len2; m->height++; g_free(value); } static void item_destroy(struct cbox_menu_item *item) { if (item->flags & mif_free_label) g_free(item->label); if (item->flags & mif_free_context) free(item->item_context); if (item->flags & mif_context_is_struct) { struct cbox_menu_item_context *ctx = item->item_context; ctx->destroy_func(ctx); } g_free(item); } static void item_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited) { int y = item->y - state->yoffset; if (y < 1 || y > state->yspace) return; if (hilited) wattron(state->window, A_REVERSE); mvwprintw(state->window, item->y - state->yoffset, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value); wattroff(state->window, A_REVERSE); } /*******************************************************************/ static gchar *command_format(const struct cbox_menu_item *item, struct cbox_menu_state *state) { return g_strdup("*"); } static int command_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key) { if (key == 10) { struct cbox_menu_item_command *citem = (struct cbox_menu_item_command *)item; return citem->execute(citem, state->context); } return 0; } struct cbox_menu_item_class menu_item_class_command = { .measure = item_measure, .draw = item_draw, .format_value = command_format, .on_idle = NULL, .on_key = command_on_key, .destroy = item_destroy }; /*******************************************************************/ void static_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited) { int y = item->y - state->yoffset; if (y < 1 || y > state->yspace) return; if (!value) { wattron(state->window, A_BOLD); mvwprintw(state->window, y, item->x, "%-*s", state->size.label_width + state->size.value_width, item->label); wattroff(state->window, A_BOLD); } else mvwprintw(state->window, y, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value); } static gchar *static_format(const struct cbox_menu_item *item, struct cbox_menu_state *state) { struct cbox_menu_item_static *sitem = (struct cbox_menu_item_static *)item; if (!sitem->format_value) return NULL; return sitem->format_value(sitem, state->context); } struct cbox_menu_item_class menu_item_class_static = { .measure = item_measure, .draw = static_draw, .format_value = static_format, .on_idle = NULL, .on_key = NULL, .destroy = item_destroy }; /*******************************************************************/ static gchar *intvalue_format(const struct cbox_menu_item *item, struct cbox_menu_state *state) { struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item; return g_strdup_printf("%d", *iitem->value); } static int intvalue_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key) { struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item; int *pv; switch(key) { case KEY_LEFT: pv = iitem->value; if (*pv > iitem->vmin) { (*pv)--; if (iitem->on_change) iitem->on_change(iitem, state->context); return -1; } return 0; case KEY_RIGHT: pv = iitem->value; if (*pv < iitem->vmax) { (*pv)++; if (iitem->on_change) iitem->on_change(iitem, state->context); return -1; } return 0; } return 0; } struct cbox_menu_item_class menu_item_class_int = { .measure = item_measure, .draw = item_draw, .format_value = intvalue_format, .on_idle = NULL, .on_key = intvalue_on_key, .destroy = item_destroy }; /*******************************************************************/ static gchar *menu_format(const struct cbox_menu_item *item, struct cbox_menu_state *state) { struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item; return g_strdup((mitem->menu || mitem->create_menu) ? "->" : "<-"); } static int menu_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key) { struct cbox_menu_page *page = state->page; if (key == 10) { struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item; if (mitem->create_menu) { struct cbox_menu_state *new_state = cbox_menu_state_new(page, mitem->create_menu(mitem, state->context), state->window, state->context); new_state->caller = state; new_state->menu_is_temporary = 1; page->state = new_state; } else if (mitem->menu) { struct cbox_menu_state *new_state = cbox_menu_state_new(page, mitem->menu, state->window, state->context); new_state->caller = state; page->state = new_state; } else { struct cbox_menu_state *caller_state = state->caller; if (state->menu_is_temporary) cbox_menu_destroy(state->menu); cbox_menu_state_destroy(state); page->state = caller_state; return -1; } return 0; } return 0; } struct cbox_menu_item_class menu_item_class_menu = { .measure = item_measure, .draw = item_draw, .format_value = menu_format, .on_idle = NULL, .on_key = menu_on_key, .destroy = item_destroy }; /*******************************************************************/ #define TREAT_LABEL(label) ((flags & mif_dup_label) == mif_dup_label ? g_strdup(label) : (char *)(label)) struct cbox_menu_item *cbox_menu_item_new_command(const char *label, cbox_menu_item_execute_func exec, void *item_context, uint32_t flags) { struct cbox_menu_item_command *item = calloc(1, sizeof(struct cbox_menu_item_command)); item->item.label = TREAT_LABEL(label); item->item.flags = flags; item->item.item_class = &menu_item_class_command; item->item.item_context = item_context; item->execute = exec; return &item->item; } struct cbox_menu_item *cbox_menu_item_new_static(const char *label, cbox_menu_item_format_value fmt, void *item_context, uint32_t flags) { struct cbox_menu_item_static *item = calloc(1, sizeof(struct cbox_menu_item_static)); item->item.label = TREAT_LABEL(label); item->item.flags = flags; item->item.item_class = &menu_item_class_static; item->item.item_context = item_context; item->format_value = fmt; return &item->item; } struct cbox_menu_item *cbox_menu_item_new_int(const char *label, int *value, int vmin, int vmax, void *item_context, uint32_t flags) { struct cbox_menu_item_int *item = calloc(1, sizeof(struct cbox_menu_item_int)); item->item.label = TREAT_LABEL(label); item->item.flags = flags; item->item.item_class = &menu_item_class_int; item->item.item_context = item_context; item->value = value; item->vmin = vmin; item->vmax = vmax; item->on_change = NULL; return &item->item; } struct cbox_menu_item *cbox_menu_item_new_menu(const char *label, struct cbox_menu *menu, void *item_context, uint32_t flags) { struct cbox_menu_item_menu *item = calloc(1, sizeof(struct cbox_menu_item_menu)); item->item.label = TREAT_LABEL(label); item->item.flags = flags; item->item.item_class = &menu_item_class_menu; item->item.item_context = item_context; item->menu = menu; item->create_menu = NULL; return &item->item; } struct cbox_menu_item *cbox_menu_item_new_dynamic_menu(const char *label, create_menu_func func, void *item_context, uint32_t flags) { struct cbox_menu_item_menu *item = calloc(1, sizeof(struct cbox_menu_item_menu)); item->item.label = TREAT_LABEL(label); item->item.flags = flags; item->item.item_class = &menu_item_class_menu; item->item.item_context = item_context; item->menu = NULL; item->create_menu = func; return &item->item; } void cbox_menu_item_destroy(struct cbox_menu_item *item) { item->item_class->destroy(item); } #endif