You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

303 lines
9.4 KiB

/*
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 <http://www.gnu.org/licenses/>.
*/
#include "menu.h"
#if USE_NCURSES
#include "menuitem.h"
#include <malloc.h>
#include <string.h>
/*******************************************************************/
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