Merge pull request #1 from atsampson/master
[calfbox.git] / menuitem.c
blob8c7dfd622d2c1e7dae010714bf3dea9975f86bf8
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "menu.h"
20 #include "menuitem.h"
21 #include <malloc.h>
22 #include <string.h>
24 /*******************************************************************/
26 static void item_measure(struct cbox_menu_item *item, struct cbox_menu_state *state)
28 struct cbox_menu_measure *m = &state->size;
29 gchar *value = item->item_class->format_value(item, state);
31 int len = strlen(item->label);
32 int len2 = value ? strlen(value) : 0;
33 if (len > m->label_width)
34 m->label_width = len;
35 if (len2 > m->value_width)
36 m->value_width = len2;
37 m->height++;
39 g_free(value);
42 static void item_destroy(struct cbox_menu_item *item)
44 g_free(item->label);
45 g_free(item);
48 static void item_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited)
50 int y = item->y - state->yoffset;
51 if (y < 1 || y > state->yspace)
52 return;
53 if (hilited)
54 wattron(state->window, A_REVERSE);
55 mvwprintw(state->window, item->y - state->yoffset, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value);
56 wattroff(state->window, A_REVERSE);
59 /*******************************************************************/
61 static gchar *command_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
63 return g_strdup("*");
66 static int command_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
68 if (key == 10)
70 struct cbox_menu_item_command *citem = (struct cbox_menu_item_command *)item;
71 return citem->execute(citem, state->context);
73 return 0;
76 struct cbox_menu_item_class menu_item_class_command = {
77 .measure = item_measure,
78 .draw = item_draw,
79 .format_value = command_format,
80 .on_idle = NULL,
81 .on_key = command_on_key,
82 .destroy = item_destroy
85 /*******************************************************************/
87 void static_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited)
89 int y = item->y - state->yoffset;
90 if (y < 1 || y > state->yspace)
91 return;
92 if (!value)
94 wattron(state->window, A_BOLD);
95 mvwprintw(state->window, y, item->x, "%-*s", state->size.label_width + state->size.value_width, item->label);
96 wattroff(state->window, A_BOLD);
98 else
99 mvwprintw(state->window, y, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value);
102 static gchar *static_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
104 struct cbox_menu_item_static *sitem = (struct cbox_menu_item_static *)item;
105 if (!sitem->format_value)
106 return NULL;
107 return sitem->format_value(sitem, state->context);
110 struct cbox_menu_item_class menu_item_class_static = {
111 .measure = item_measure,
112 .draw = static_draw,
113 .format_value = static_format,
114 .on_idle = NULL,
115 .on_key = NULL,
116 .destroy = item_destroy
119 /*******************************************************************/
121 static gchar *intvalue_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
123 struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item;
125 return g_strdup_printf("%d", *iitem->value);
128 static int intvalue_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
130 struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item;
131 int *pv;
133 switch(key)
135 case KEY_LEFT:
136 pv = iitem->value;
137 if (*pv > iitem->vmin)
139 (*pv)--;
140 if (iitem->on_change)
141 iitem->on_change(iitem, state->context);
142 return -1;
144 return 0;
145 case KEY_RIGHT:
146 pv = iitem->value;
147 if (*pv < iitem->vmax)
149 (*pv)++;
150 if (iitem->on_change)
151 iitem->on_change(iitem, state->context);
152 return -1;
154 return 0;
156 return 0;
159 struct cbox_menu_item_class menu_item_class_int = {
160 .measure = item_measure,
161 .draw = item_draw,
162 .format_value = intvalue_format,
163 .on_idle = NULL,
164 .on_key = intvalue_on_key,
165 .destroy = item_destroy
169 /*******************************************************************/
171 static gchar *menu_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
173 struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item;
175 return g_strdup((mitem->menu || mitem->create_menu) ? "->" : "<-");
178 static int menu_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
180 if (key == 10)
182 struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item;
183 if (mitem->create_menu)
185 struct cbox_menu_state *new_state = cbox_menu_state_new(state->page, mitem->create_menu(mitem, state->context), state->window, state->context);
186 new_state->caller = state;
187 state->page->state = new_state;
189 else
190 if (mitem->menu)
192 struct cbox_menu_state *new_state = cbox_menu_state_new(state->page, mitem->menu, state->window, state->context);
193 new_state->caller = state;
194 state->page->state = new_state;
196 else
198 struct cbox_menu_state *old_state = state;
199 state->page->state = state->caller;
200 if (old_state->menu_is_temporary)
201 cbox_menu_destroy(old_state->menu);
202 cbox_menu_state_destroy(old_state);
203 return -1;
205 return 0;
207 return 0;
210 struct cbox_menu_item_class menu_item_class_menu = {
211 .measure = item_measure,
212 .draw = item_draw,
213 .format_value = menu_format,
214 .on_idle = NULL,
215 .on_key = menu_on_key,
216 .destroy = item_destroy
219 /*******************************************************************/
221 struct cbox_menu_item *cbox_menu_item_new_command(const char *label, cbox_menu_item_execute_func exec, void *item_context)
223 struct cbox_menu_item_command *item = malloc(sizeof(struct cbox_menu_item_command));
224 item->item.label = g_strdup(label);
225 item->item.item_class = &menu_item_class_command;
226 item->item.item_context = item_context;
227 item->execute = exec;
228 return &item->item;
231 struct cbox_menu_item *cbox_menu_item_new_static(const char *label, cbox_menu_item_format_value fmt, void *item_context)
233 struct cbox_menu_item_static *item = malloc(sizeof(struct cbox_menu_item_static));
234 item->item.label = g_strdup(label);
235 item->item.item_class = &menu_item_class_static;
236 item->item.item_context = item_context;
237 item->format_value = fmt;
238 return &item->item;
241 struct cbox_menu_item *cbox_menu_item_new_int(const char *label, int *value, int vmin, int vmax, void *item_context)
243 struct cbox_menu_item_int *item = malloc(sizeof(struct cbox_menu_item_int));
244 item->item.label = g_strdup(label);
245 item->item.item_class = &menu_item_class_int;
246 item->item.item_context = item_context;
247 item->value = value;
248 item->vmin = vmin;
249 item->vmax = vmax;
250 item->on_change = NULL;
251 return &item->item;
254 struct cbox_menu_item *cbox_menu_item_new_menu(const char *label, struct cbox_menu *menu, void *item_context)
256 struct cbox_menu_item_menu *item = malloc(sizeof(struct cbox_menu_item_menu));
257 item->item.label = g_strdup(label);
258 item->item.item_class = &menu_item_class_menu;
259 item->item.item_context = item_context;
260 item->menu = menu;
261 item->create_menu = NULL;
262 return &item->item;
265 struct cbox_menu_item *cbox_menu_item_new_dynamic_menu(const char *label, create_menu_func func, void *item_context)
267 struct cbox_menu_item_menu *item = malloc(sizeof(struct cbox_menu_item_menu));
268 item->item.label = g_strdup(label);
269 item->item.item_class = &menu_item_class_menu;
270 item->item.item_context = item_context;
271 item->menu = NULL;
272 item->create_menu = func;
273 return &item->item;
276 void cbox_menu_item_destroy(struct cbox_menu_item *item)
278 item->item_class->destroy(item);