Menustuff added/modified!
This commit is contained in:
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* menuitem.c
|
||||
* This file is part of LCDd, the lcdproc server.
|
||||
*
|
||||
* This file is released under the GNU General Public License. Refer to the
|
||||
* COPYING file distributed with this package.
|
||||
*
|
||||
* Copyright (c) 1999, William Ferrell, Scott Scriven
|
||||
* 2002, Joris Robijn
|
||||
*
|
||||
*
|
||||
* Handles a menuitem and all actions that can be performed on it.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "shared/report.h"
|
||||
|
||||
#include "menuitem.h"
|
||||
#include "menu.h"
|
||||
#include "drivers.h"
|
||||
|
||||
#define MAX_NUMERIC_LEN 40
|
||||
|
||||
char *error_strs[] = {"", "Out of range", "Too long", "Too short"};
|
||||
|
||||
void menuitem_destroy_action (MenuItem *item);
|
||||
void menuitem_destroy_checkbox (MenuItem *item);
|
||||
void menuitem_destroy_ring (MenuItem *item);
|
||||
void menuitem_destroy_slider (MenuItem *item);
|
||||
void menuitem_destroy_numeric (MenuItem *item);
|
||||
void menuitem_destroy_alpha (MenuItem *item);
|
||||
|
||||
void menuitem_reset_numeric (MenuItem *item);
|
||||
void menuitem_reset_alpha (MenuItem *item);
|
||||
|
||||
void menuitem_build_screen_slider (MenuItem *item, Screen *s);
|
||||
void menuitem_build_screen_numeric (MenuItem *item, Screen *s);
|
||||
void menuitem_build_screen_alpha (MenuItem *item, Screen *s);
|
||||
|
||||
void menuitem_update_screen_slider (MenuItem *item, Screen *s);
|
||||
void menuitem_update_screen_numeric (MenuItem *item, Screen *s);
|
||||
void menuitem_update_screen_alpha (MenuItem *item, Screen *s);
|
||||
|
||||
MenuResult menuitem_handle_input_slider (MenuItem *item, MenuToken token, char * key);
|
||||
MenuResult menuitem_handle_input_numeric (MenuItem *item, MenuToken token, char * key);
|
||||
MenuResult menuitem_handle_input_alpha (MenuItem *item, MenuToken token, char * key);
|
||||
|
||||
/******** FUNCTION TABLES ********/
|
||||
/* Tables with functions to call for all different item types */
|
||||
|
||||
void (*destructor_table[NUM_ITEMTYPES] ) (MenuItem *item) =
|
||||
{
|
||||
menu_destroy,
|
||||
NULL,
|
||||
menuitem_destroy_ring,
|
||||
menuitem_destroy_slider,
|
||||
menuitem_destroy_numeric,
|
||||
menuitem_destroy_alpha
|
||||
};
|
||||
void (*reset_table[NUM_ITEMTYPES] ) (MenuItem *item) =
|
||||
{
|
||||
menu_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
menuitem_reset_numeric,
|
||||
menuitem_reset_alpha
|
||||
};
|
||||
void (*build_screen_table[NUM_ITEMTYPES] ) (MenuItem *item, Screen *s) =
|
||||
{
|
||||
menu_build_screen,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
menuitem_build_screen_slider,
|
||||
menuitem_build_screen_numeric,
|
||||
menuitem_build_screen_alpha
|
||||
};
|
||||
void (*update_screen_table[NUM_ITEMTYPES] ) (MenuItem *item, Screen *s) =
|
||||
{
|
||||
menu_update_screen,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
menuitem_update_screen_slider,
|
||||
menuitem_update_screen_numeric,
|
||||
menuitem_update_screen_alpha
|
||||
};
|
||||
|
||||
MenuResult (*handle_input_table[NUM_ITEMTYPES] ) (MenuItem *item, MenuToken token, char *key) =
|
||||
{
|
||||
menu_handle_input,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
menuitem_handle_input_slider,
|
||||
menuitem_handle_input_numeric,
|
||||
menuitem_handle_input_alpha
|
||||
};
|
||||
|
||||
/******** METHODS ********/
|
||||
|
||||
MenuItem *menuitem_create (MenuItemType type, char *id, MenuEventFunc(*event_func),
|
||||
char *text)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
|
||||
debug (RPT_DEBUG, "%s( type=%d, id=\"%s\", event_func=%p, text=\"%s\" )",
|
||||
__FUNCTION__, type, id, event_func, text);
|
||||
|
||||
/* Allocate space and fill struct */
|
||||
new_item = malloc (sizeof(MenuItem));
|
||||
if (!new_item) {
|
||||
report (RPT_ERR, "%s: Could not allocate memory", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
new_item->type = type;
|
||||
new_item->id = strdup (id);
|
||||
if (!new_item->id) {
|
||||
report (RPT_ERR, "%s: Could not allocate memory", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
new_item->parent = NULL;
|
||||
new_item->event_func = event_func;
|
||||
new_item->text = strdup (text);
|
||||
if (!new_item->text) {
|
||||
report (RPT_ERR, "%s: Could not allocate memory", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clear the type specific data part */
|
||||
memset ( &(new_item->data), 0, sizeof(new_item->data));
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_action (char *id, MenuEventFunc(*event_func),
|
||||
char *text, bool close_menu, bool quit_menu)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", close_menu=%d )",
|
||||
__FUNCTION__, id, event_func, text, close_menu);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_ACTION, id, event_func, text);
|
||||
new_item->data.action.close_menu = close_menu;
|
||||
new_item->data.action.quit_menu = quit_menu;
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_checkbox (char *id, MenuEventFunc(*event_func),
|
||||
char *text, bool allow_gray, bool value)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", allow_gray=%d, value=%d )",
|
||||
__FUNCTION__, id, event_func, text, allow_gray, value);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_CHECKBOX, id, event_func, text);
|
||||
new_item->data.checkbox.allow_gray = allow_gray;
|
||||
new_item->data.checkbox.value = value;
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_ring (char *id, MenuEventFunc(*event_func),
|
||||
char *text, char *strings, short value)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
char *tabptr, *p, *new_s;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", strings=\"%s\", value=%d )",
|
||||
__FUNCTION__, id, event_func, text, strings, value);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_RING, id, event_func, text);
|
||||
|
||||
/* parse strings */
|
||||
p = strings;
|
||||
new_item->data.ring.strings = LL_new();
|
||||
while ((tabptr = strchr(p, '\t')) != NULL) {
|
||||
int len = (int)(tabptr - p);
|
||||
|
||||
/* Alloc and copy substring */
|
||||
new_s = malloc (len + 1);
|
||||
strncpy (new_s, p, len);
|
||||
new_s[len] = 0;
|
||||
|
||||
LL_Push (new_item->data.ring.strings, new_s);
|
||||
|
||||
/* Go to next string */
|
||||
p = tabptr + 1;
|
||||
}
|
||||
/* Add last string */
|
||||
new_s = strdup (p);
|
||||
LL_Push (new_item->data.ring.strings, new_s);
|
||||
|
||||
new_item->data.ring.value = value;
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_slider (char *id, MenuEventFunc(*event_func),
|
||||
char *text, char *mintext, char *maxtext,
|
||||
int minvalue, int maxvalue, int stepsize, int value)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", mintext=\"%s\", maxtext=\"%s\", minvalue=%d, maxvalue=%d, stepsize=%d, value=%d )",
|
||||
__FUNCTION__, id, event_func, text, mintext, maxtext, minvalue, maxvalue, stepsize, value);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_SLIDER, id, event_func, text);
|
||||
new_item->data.slider.mintext = strdup (mintext);
|
||||
new_item->data.slider.maxtext = strdup (maxtext);
|
||||
new_item->data.slider.minvalue = minvalue;
|
||||
new_item->data.slider.maxvalue = maxvalue;
|
||||
new_item->data.slider.stepsize = stepsize;
|
||||
new_item->data.slider.value = value;
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_numeric (char *id, MenuEventFunc(*event_func),
|
||||
char *text, int minvalue, int maxvalue, int value)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", minvalue=%d, maxvalue=%d, value=%d )",
|
||||
__FUNCTION__, id, event_func, text, minvalue, minvalue, value);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_NUMERIC, id, event_func, text);
|
||||
new_item->data.numeric.maxvalue = maxvalue;
|
||||
new_item->data.numeric.minvalue = minvalue;
|
||||
new_item->data.numeric.edit_str = malloc (MAX_NUMERIC_LEN);
|
||||
new_item->data.numeric.value = value;
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
MenuItem *menuitem_create_alpha (char *id, MenuEventFunc(*event_func),
|
||||
char *text, char password_char, short minlength, short maxlength,
|
||||
bool allow_caps, bool allow_noncaps, bool allow_numbers,
|
||||
char *allowed_extra, char *value)
|
||||
{
|
||||
MenuItem *new_item;
|
||||
char * chars;
|
||||
|
||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", password_char=%d, maxlength=%d, value=\"%s\" )",
|
||||
__FUNCTION__, id, event_func, text, password_char, maxlength, value);
|
||||
|
||||
new_item = menuitem_create (MENUITEM_ALPHA, id, event_func, text);
|
||||
new_item->data.alpha.password_char = password_char;
|
||||
new_item->data.alpha.minlength = minlength;
|
||||
new_item->data.alpha.maxlength = maxlength;
|
||||
|
||||
new_item->data.alpha.value = malloc (maxlength + 1);
|
||||
strncpy (new_item->data.alpha.value, value, maxlength);
|
||||
new_item->data.alpha.value[maxlength] = 0;
|
||||
|
||||
/* Create list of allowed chars */
|
||||
chars = malloc (26 + 26 + 10 + strlen(allowed_extra) + 1);
|
||||
chars[0] = 0;
|
||||
if (allow_caps)
|
||||
strcat (chars, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
if (allow_noncaps)
|
||||
strcat (chars, "abcdefghijklmnopqrstuvwxyz");
|
||||
if (allow_numbers)
|
||||
strcat (chars, "0123456789");
|
||||
if (allowed_extra) {
|
||||
strcat (chars, allowed_extra);
|
||||
}
|
||||
new_item->data.alpha.allowed_chars = chars;
|
||||
|
||||
new_item->data.alpha.edit_str = malloc (maxlength + 1);
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
|
||||
void menuitem_destroy (MenuItem *item)
|
||||
{
|
||||
void (*destructor) (MenuItem *);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* First destroy type specific data */
|
||||
destructor = destructor_table[item->type];
|
||||
if (destructor)
|
||||
destructor (item);
|
||||
|
||||
/* Following strings should always be allocated */
|
||||
free (item->text);
|
||||
free (item->id);
|
||||
|
||||
/* And finally...*/
|
||||
free (item);
|
||||
}
|
||||
|
||||
void menuitem_destroy_ring (MenuItem *item)
|
||||
{
|
||||
char * s;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* deallocate the strings */
|
||||
for (s = LL_GetFirst(item->data.ring.strings); s; s = LL_GetNext(item->data.ring.strings)) {
|
||||
free (s);
|
||||
}
|
||||
/* and the list */
|
||||
LL_Destroy (item->data.ring.strings);
|
||||
}
|
||||
|
||||
void menuitem_destroy_slider (MenuItem *item)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* These strings should always be allocated */
|
||||
free (item->data.slider.mintext);
|
||||
free (item->data.slider.maxtext);
|
||||
}
|
||||
|
||||
void menuitem_destroy_numeric (MenuItem *item)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* This string should always be allocated */
|
||||
free (item->data.alpha.edit_str);
|
||||
}
|
||||
|
||||
void menuitem_destroy_alpha (MenuItem *item)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* These strings should always be allocated */
|
||||
free (item->data.alpha.allowed_chars);
|
||||
free (item->data.alpha.value);
|
||||
free (item->data.alpha.edit_str);
|
||||
}
|
||||
|
||||
/******** MENU ITEM RESET FUNCTIONS ********/
|
||||
|
||||
void menuitem_reset (MenuItem *item)
|
||||
{
|
||||
void (*func) (MenuItem *);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
/* First destroy type specific data */
|
||||
func = reset_table[item->type];
|
||||
if (func)
|
||||
func (item);
|
||||
}
|
||||
|
||||
void menuitem_reset_numeric (MenuItem *item)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
item->data.numeric.edit_pos = 0;
|
||||
memset ( item->data.numeric.edit_str, 0, MAX_NUMERIC_LEN);
|
||||
if (item->data.numeric.minvalue < 0) {
|
||||
snprintf (item->data.numeric.edit_str, MAX_NUMERIC_LEN, "%+d", item->data.numeric.value);
|
||||
} else {
|
||||
snprintf (item->data.numeric.edit_str, MAX_NUMERIC_LEN, "%d", item->data.numeric.value);
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_reset_alpha (MenuItem *item)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\" )", __FUNCTION__, item->id);
|
||||
|
||||
item->data.alpha.edit_pos = 0;
|
||||
memset (item->data.alpha.edit_str, 0, item->data.alpha.maxlength+1);
|
||||
strcpy (item->data.alpha.edit_str, item->data.alpha.value);
|
||||
}
|
||||
|
||||
|
||||
/******** MENU SCREEN BUILD FUNCTIONS ********/
|
||||
|
||||
void menuitem_build_screen (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
void (*build_screen) (MenuItem *item, Screen *s);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
if (!display_props) {
|
||||
/* Nothing to build if no display size is known */
|
||||
report (RPT_ERR, "%s: display size unknown", __FUNCTION__ );
|
||||
return;
|
||||
}
|
||||
|
||||
/* First remove all widgets from the screen */
|
||||
while ( (w = screen_getfirst_widget(s)) ) {
|
||||
/* We know these widgets don't have subwidgets, so we can
|
||||
* easily remove them
|
||||
*/
|
||||
screen_remove_widget (s, w);
|
||||
widget_destroy (w);
|
||||
}
|
||||
|
||||
/* Call type specific screen building function */
|
||||
build_screen = build_screen_table [item->type];
|
||||
if (build_screen) {
|
||||
build_screen (item, s);
|
||||
} else {
|
||||
report (RPT_ERR, "%s: given menuitem cannot be active", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_build_screen_slider (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
if (display_props->height >= 2 ) {
|
||||
/* Only add a title if enough space... */
|
||||
w = widget_create ("text", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = strdup(item->text);
|
||||
w->x = 1;
|
||||
w->y = 1;
|
||||
}
|
||||
|
||||
w = widget_create ("bar", WID_HBAR, s);
|
||||
screen_add_widget (s, w);
|
||||
w->width = display_props->width;
|
||||
if (display_props->height > 2 ) {
|
||||
/* This is option 1: we have enought space, so the bar and
|
||||
* min/max texts can be on separate lines.
|
||||
*/
|
||||
w->x = 2;
|
||||
w->y = display_props->height / 2 + 1;
|
||||
w->length = display_props->width - 2;
|
||||
}
|
||||
|
||||
w = widget_create ("min", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = NULL;
|
||||
w->x = 1;
|
||||
if (display_props->height > 2 ) {
|
||||
w->y = display_props->height / 2 + 2;
|
||||
} else {
|
||||
w->y = display_props->height / 2 + 1;
|
||||
}
|
||||
|
||||
w = widget_create ("max", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = NULL;
|
||||
w->x = 1;
|
||||
if (display_props->height > 2 ) {
|
||||
w->y = display_props->height / 2 + 2;
|
||||
} else {
|
||||
w->y = display_props->height / 2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_build_screen_numeric (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
if (display_props->height >= 2 ) {
|
||||
/* Only add a title if enough space... */
|
||||
w = widget_create ("text", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = strdup(item->text);
|
||||
w->x = 1;
|
||||
w->y = 1;
|
||||
}
|
||||
|
||||
w = widget_create ("value", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = malloc (MAX_NUMERIC_LEN);
|
||||
w->x = 2;
|
||||
w->y = display_props->height / 2 + 1;
|
||||
|
||||
/* Only display error string if enough space... */
|
||||
if (display_props->height > 2 ) {
|
||||
w = widget_create ("error", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = strdup("");
|
||||
w->x = 1;
|
||||
w->y = display_props->height;
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_build_screen_alpha (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
if (display_props->height >= 2 ) {
|
||||
/* Only add a title if enough space... */
|
||||
w = widget_create ("text", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = strdup(item->text);
|
||||
w->x = 1;
|
||||
w->y = 1;
|
||||
}
|
||||
|
||||
w = widget_create ("value", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = malloc (item->data.alpha.maxlength+1);
|
||||
w->x = 2;
|
||||
w->y = display_props->height / 2 + 1;
|
||||
|
||||
/* Only display error string if enough space... */
|
||||
if (display_props->height > 2 ) {
|
||||
w = widget_create ("error", WID_STRING, s);
|
||||
screen_add_widget (s, w);
|
||||
w->text = strdup("");
|
||||
w->x = 1;
|
||||
w->y = display_props->height;
|
||||
}
|
||||
}
|
||||
|
||||
/******** MENU SCREEN UPDATE FUNCTIONS ********/
|
||||
|
||||
void menuitem_update_screen (MenuItem *item, Screen *s)
|
||||
{
|
||||
void (*update_screen) (MenuItem *item, Screen *s);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
/* Disable the cursor by default */
|
||||
s->cursor = CURSOR_OFF;
|
||||
|
||||
/* Call type specific screen building function */
|
||||
update_screen = update_screen_table [item->type];
|
||||
if (update_screen) {
|
||||
update_screen (item, s);
|
||||
} else {
|
||||
report (RPT_ERR, "%s: given menuitem cannot be active", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_update_screen_slider (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
int min_len, max_len;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
/* Calculate the bar position and length by filling buffers */
|
||||
min_len = strlen (item->data.slider.mintext);
|
||||
max_len = strlen (item->data.slider.maxtext);
|
||||
|
||||
/* And adjust the data */
|
||||
|
||||
w = screen_find_widget (s, "bar");
|
||||
if (display_props->height <= 2 ) {
|
||||
/* This is option 2: we're tight on lines, so we put the bar
|
||||
* and min/max texts on the same line.
|
||||
*/
|
||||
w->x = 1 + min_len;
|
||||
w->y = display_props->height;
|
||||
w->width = display_props->width -
|
||||
min_len - max_len;
|
||||
}
|
||||
/* FUTURE: w->promille = 1000 * (item->data.slider.value - item->data.slider.minvalue) / (item->data.slider.maxvalue - item->data.slider.minvalue) */;
|
||||
w->length = w->width * display_props->cellwidth
|
||||
* (item->data.slider.value - item->data.slider.minvalue)
|
||||
/ (item->data.slider.maxvalue - item->data.slider.minvalue);
|
||||
|
||||
w = screen_find_widget (s, "min");
|
||||
if (w->text) free (w->text);
|
||||
w->text = strdup(item->data.slider.mintext);
|
||||
|
||||
w = screen_find_widget (s, "max");
|
||||
if (w->text) free (w->text);
|
||||
w->x = 1 + display_props->width - max_len;
|
||||
w->text = strdup(item->data.slider.maxtext);
|
||||
}
|
||||
|
||||
void menuitem_update_screen_numeric (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
w = screen_find_widget (s, "value");
|
||||
strcpy (w->text, item->data.numeric.edit_str);
|
||||
|
||||
s->cursor = CURSOR_DEFAULT_ON;
|
||||
s->cursor_x = w->x + item->data.numeric.edit_pos;
|
||||
s->cursor_y = w->y;
|
||||
|
||||
/* Only display error string if enough space... */
|
||||
if (display_props->height > 2 ) {
|
||||
w = screen_find_widget (s, "error");
|
||||
free (w->text);
|
||||
w->text = strdup (error_strs[item->data.numeric.error_code]);
|
||||
}
|
||||
}
|
||||
|
||||
void menuitem_update_screen_alpha (MenuItem *item, Screen *s)
|
||||
{
|
||||
Widget * w;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", screen=\"%s\" )", __FUNCTION__, item->id, s->id);
|
||||
|
||||
w = screen_find_widget (s, "value");
|
||||
if (item->data.alpha.password_char == 0) {
|
||||
strcpy (w->text, item->data.alpha.edit_str);
|
||||
} else {
|
||||
memset (item->data.alpha.edit_str, 0, item->data.alpha.maxlength+1);
|
||||
memset (item->data.alpha.edit_str, item->data.alpha.password_char, strlen (item->data.alpha.edit_str));
|
||||
}
|
||||
|
||||
s->cursor = CURSOR_DEFAULT_ON;
|
||||
s->cursor_x = w->x + item->data.alpha.edit_pos;
|
||||
s->cursor_y = w->y;
|
||||
|
||||
/* Only display error string if enough space... */
|
||||
if (display_props->height > 2 ) {
|
||||
w = screen_find_widget (s, "error");
|
||||
free (w->text);
|
||||
w->text = strdup (error_strs[item->data.alpha.error_code]);
|
||||
}
|
||||
}
|
||||
|
||||
/******** MENU SCREEN INPUT HANDLING FUNCTIONS ********/
|
||||
|
||||
MenuResult menuitem_handle_input (MenuItem *item, MenuToken token, char * key)
|
||||
{
|
||||
MenuResult (*handle_input) (MenuItem *item, MenuToken token, char * key);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", token=%d, key=\"%s\" )", __FUNCTION__, item->id, token, key);
|
||||
|
||||
/* Call type specific screen building function */
|
||||
handle_input = handle_input_table [item->type];
|
||||
if (handle_input ) {
|
||||
return handle_input (item, token, key);
|
||||
} else {
|
||||
report (RPT_ERR, "%s: given menuitem cannot be active", __FUNCTION__);
|
||||
return MENURESULT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
MenuResult menuitem_handle_input_slider (MenuItem *item, MenuToken token, char * key)
|
||||
{
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", token=%d, key=\"%s\" )", __FUNCTION__, item->id, token, key);
|
||||
|
||||
switch (token) {
|
||||
case MENUTOKEN_MENU:
|
||||
case MENUTOKEN_ENTER:
|
||||
return MENURESULT_CLOSE;
|
||||
case MENUTOKEN_UP:
|
||||
item->data.slider.value = min (item->data.slider.maxvalue,
|
||||
item->data.slider.value + item->data.slider.stepsize);
|
||||
if (item->event_func)
|
||||
item->event_func (item, MENUEVENT_PLUS);
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_DOWN:
|
||||
item->data.slider.value = max (item->data.slider.minvalue,
|
||||
item->data.slider.value - item->data.slider.stepsize);
|
||||
if (item->event_func)
|
||||
item->event_func (item, MENUEVENT_MINUS);
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_OTHER:
|
||||
}
|
||||
|
||||
return MENURESULT_ERROR;
|
||||
}
|
||||
|
||||
MenuResult menuitem_handle_input_numeric (MenuItem *item, MenuToken token, char * key)
|
||||
{
|
||||
char buf1[MAX_NUMERIC_LEN];
|
||||
char buf2[MAX_NUMERIC_LEN];
|
||||
|
||||
char *format_str;
|
||||
int max_len;
|
||||
|
||||
/* To make life easy... */
|
||||
char *str = item->data.numeric.edit_str;
|
||||
int pos = item->data.numeric.edit_pos;
|
||||
int allow_signed = (item->data.numeric.minvalue < 0);
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", token=%d, key=\"%s\" )", __FUNCTION__, item->id, token, key);
|
||||
|
||||
if (allow_signed) {
|
||||
format_str = "%+d";
|
||||
} else {
|
||||
format_str = "%d";
|
||||
}
|
||||
snprintf (buf1, MAX_NUMERIC_LEN, format_str, item->data.numeric.minvalue);
|
||||
snprintf (buf2, MAX_NUMERIC_LEN, format_str, item->data.numeric.maxvalue);
|
||||
|
||||
max_len = max (strlen(buf1), strlen(buf2));
|
||||
|
||||
/* Clear the error */
|
||||
item->data.numeric.error_code = 0;
|
||||
|
||||
switch (token) {
|
||||
case MENUTOKEN_MENU:
|
||||
if (pos == 0) {
|
||||
return MENURESULT_CLOSE;
|
||||
}
|
||||
else {
|
||||
/* Reset data */
|
||||
item->data.numeric.edit_pos = 0;
|
||||
memset (str, 0, MAX_NUMERIC_LEN);
|
||||
snprintf (str, MAX_NUMERIC_LEN, format_str, item->data.numeric.value);
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_ENTER:
|
||||
if (str[pos] == 0) {
|
||||
int value;
|
||||
/* The user completed his input */
|
||||
|
||||
/* ...scan it */
|
||||
if (sscanf (str, "%d", &value) != 1) {
|
||||
return MENURESULT_ERROR;
|
||||
}
|
||||
/* Test the value */
|
||||
if (value < item->data.numeric.minvalue
|
||||
|| value > item->data.numeric.maxvalue) {
|
||||
/* Out of range !
|
||||
* We can't exit this screen now
|
||||
*/
|
||||
item->data.numeric.error_code = 1;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
|
||||
/* OK, store value */
|
||||
item->data.numeric.value = value;
|
||||
|
||||
/* Inform client */
|
||||
if (item->event_func)
|
||||
item->event_func (item, MENUEVENT_UPDATE);
|
||||
|
||||
return MENURESULT_CLOSE;
|
||||
}
|
||||
else {
|
||||
/* The user wants to go to next digit */
|
||||
if (pos < max_len) {
|
||||
item->data.numeric.edit_pos ++;
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_UP:
|
||||
if (pos >= max_len) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.numeric.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
if (allow_signed && pos == 0) {
|
||||
/* make negative */
|
||||
str[0] = (str[0] == '-') ? '+' : '-';
|
||||
}
|
||||
else {
|
||||
if (str[pos] >= '0' && str[pos] < '9') {
|
||||
str[pos] ++;
|
||||
} else if (str[pos] == '9') {
|
||||
str[pos] = 0;
|
||||
} else if (str[pos] == 0) {
|
||||
str[pos] = '0';
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_DOWN:
|
||||
if (pos >= max_len) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.numeric.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
if (allow_signed && pos == 0) {
|
||||
/* make negative */
|
||||
str[0] = (str[0] == '-') ? '+' : '-';
|
||||
}
|
||||
else {
|
||||
if (str[pos] > '0' && str[pos] <= '9') {
|
||||
str[pos] --;
|
||||
} else if (str[pos] == '0') {
|
||||
str[pos] = 0;
|
||||
} else if (str[pos] == 0) {
|
||||
str[pos] = '9';
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_OTHER:
|
||||
if (pos >= max_len) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.numeric.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
/* proces numeric keys */
|
||||
if ( strlen(key) == 1 && key[0] >= '0' && key[0] <= '9') {
|
||||
str[pos] = key[0];
|
||||
item->data.numeric.edit_pos ++;
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
return MENURESULT_ERROR;
|
||||
}
|
||||
|
||||
MenuResult menuitem_handle_input_alpha (MenuItem *item, MenuToken token, char * key)
|
||||
{
|
||||
char * p;
|
||||
char * chars = item->data.alpha.allowed_chars;
|
||||
|
||||
/* To make life easy... */
|
||||
char *str = item->data.alpha.edit_str;
|
||||
int pos = item->data.alpha.edit_pos;
|
||||
|
||||
debug (RPT_DEBUG, "%s( item=\"%s\", token=%d, key=\"%s\" )", __FUNCTION__, item->id, token, key);
|
||||
|
||||
/* Clear the error */
|
||||
item->data.alpha.error_code = 0;
|
||||
|
||||
switch (token) {
|
||||
case MENUTOKEN_MENU:
|
||||
if (pos == 0) {
|
||||
return MENURESULT_CLOSE;
|
||||
}
|
||||
else {
|
||||
/* Reset data */
|
||||
item->data.alpha.edit_pos = 0;
|
||||
memset (str, 0, item->data.alpha.maxlength+1);
|
||||
strcpy (str, item->data.alpha.value);
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_ENTER:
|
||||
if (str[item->data.alpha.edit_pos] == 0) {
|
||||
/* The user completed his input */
|
||||
|
||||
/* It's not too short ? */
|
||||
if (strlen (item->data.alpha.edit_str) < item->data.alpha.minlength) {
|
||||
item->data.alpha.error_code = 3;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
|
||||
/* Store value */
|
||||
strcpy (item->data.alpha.value, item->data.alpha.edit_str);
|
||||
|
||||
/* Inform client */
|
||||
if (item->event_func)
|
||||
item->event_func (item, MENUEVENT_UPDATE);
|
||||
|
||||
return MENURESULT_CLOSE;
|
||||
}
|
||||
else {
|
||||
/* The user wants to go to next digit */
|
||||
if (pos < item->data.alpha.maxlength) {
|
||||
item->data.alpha.edit_pos ++;
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_UP:
|
||||
if (pos >= item->data.alpha.maxlength) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.alpha.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
if (str[pos] == 0) {
|
||||
/* User goes past EOL */
|
||||
str[pos] = chars[0];
|
||||
} else {
|
||||
/* We should have a symbol from our list */
|
||||
p = strchr (chars, str[pos]);
|
||||
if (p != NULL) {
|
||||
str[pos] = * (++p); /* next symbol on list */
|
||||
/* Might be 0 now */
|
||||
} else {
|
||||
str[pos] = 0;
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_DOWN:
|
||||
if (pos >= item->data.alpha.maxlength) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.alpha.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
if (str[pos] == 0) {
|
||||
/* User goes past EOL */
|
||||
str[pos] = chars[strlen(chars)-1];
|
||||
} else {
|
||||
/* We should have a symbol from our list */
|
||||
p = strchr (chars, str[pos]);
|
||||
if (p != NULL) {
|
||||
if (p == chars) {
|
||||
str[pos] = 0; /* Go to EOL */
|
||||
} else {
|
||||
str[pos] = * (--p); /* next symbol on list */
|
||||
}
|
||||
} else {
|
||||
str[pos] = 0;
|
||||
}
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
case MENUTOKEN_OTHER:
|
||||
if (pos >= item->data.alpha.maxlength) {
|
||||
/* We're not allowed to add anything anymore */
|
||||
item->data.alpha.error_code = 2;
|
||||
item->data.numeric.edit_pos = 0;
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
/* proces other keys */
|
||||
if ( strlen(key) == 1 && key[0] >= ' ' && key[0] <= 'Z') {
|
||||
str[pos] = key[0];
|
||||
item->data.alpha.edit_pos ++;
|
||||
}
|
||||
return MENURESULT_OK;
|
||||
}
|
||||
return MENURESULT_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user