Menustuff added/modified!

This commit is contained in:
robijn
2002-05-26 19:21:23 +00:00
parent dc4c049721
commit 3168d4cafc
27 changed files with 2304 additions and 584 deletions
+21 -2
View File
@@ -83,6 +83,14 @@ DriverPath=server/drivers/
# Always place a slash as last character !
[menu]
# The menu section. You can configure what keys the menu should use.
# Note that only the menukey will be reserved exclusively.
MenuKey=Escape
EnterKey=Enter
UpKey=Up
DownKey=Down
# Driver sections are below this line, in alphabetical order
@@ -194,8 +202,8 @@ ConnectionType=4bit
# Select what type of connection. See documentation for types.
Keypad=no
# If you have a keypad connected. Keypad layout is currently not
# configureable from the config file.
# If you have a keypad connected.
# You may also need to configure the keypad layout further on in this file.
Backlight=no
# If you have a switchable backlight.
@@ -222,6 +230,17 @@ DelayBus=true
# On fast PCs it is possible your LCD does not respond correctly.
# Default: true.
# If you have a keypad you can assign keystrings to the keys.
# See documentation for used terms and how to wire it.
# For example to give directly connected key 4 the string "Enter", use:
# KeyDirect_4=Enter
# For matrix keys use the X and Y coordinates of the key:
# KeyMatrix_1_3=Enter
KeyMatrix_4_1=Enter
KeyMatrix_4_2=Up
KeyMatrix_4_3=Down
KeyMatrix_4_4=Escape
[IrMan]
+1 -1
View File
@@ -1,5 +1,5 @@
SUBDIRS=drivers commands
sbin_PROGRAMS=LCDd
LCDd_SOURCES= client.c client.h clients.c clients.h client_menu.h input.c input.h main.c main.h menu.c menu.h menuscreens.c menuscreens.h parse.c parse.h render.c render.h screen.c screen.h screenlist.c screenlist.h serverscreens.c serverscreens.h sock.c sock.h widget.c widget.h configfile.c configfile.h drivers.c drivers.h driver.c driver.h
LCDd_SOURCES= client.c client.h clients.c clients.h input.c input.h main.c main.h menuitem.c menuitem.h menu.c menu.h menuscreens.c menuscreens.h parse.c parse.h render.c render.h screen.c screen.h screenlist.c screenlist.h serverscreens.c serverscreens.h sock.c sock.h widget.c widget.h configfile.c configfile.h drivers.c drivers.h driver.c driver.h
LCDd_LDADD = ../shared/libLCDstuff.a commands/libLCDcommands.a
INCLUDES = -I$(top_srcdir)
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* client_data.h
* client.c
* This file is part of LCDd, the lcdproc server.
*
* This file is released under the GNU General Public License. Refer to the
@@ -260,4 +260,4 @@ client_remove_screen (Client * c, Screen * s)
int client_screen_count (Client * c)
{
return LL_Length(c->screenlist);
}
}
-1
View File
@@ -20,7 +20,6 @@
#include <unistd.h>
#include <string.h>
#include "sock.h"
#include "client.h"
#include "clients.h"
#include "shared/report.h"
+15 -9
View File
@@ -312,7 +312,7 @@ driver_alt_vbar( Driver * drv, int x, int y, int len, int promille, int pattern
{
int pos;
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d", __FILE__, drv->name, x, y, len, promille, pattern);
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d )", __FUNCTION__, drv->name, x, y, len, promille, pattern);
if (!drv->chr)
return;
@@ -330,7 +330,7 @@ driver_alt_hbar( Driver * drv, int x, int y, int len, int promille, int pattern
{
int pos;
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d", __FILE__, drv->name, x, y, len, promille, pattern);
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d )", __FUNCTION__, drv->name, x, y, len, promille, pattern);
if (!drv->chr)
return;
@@ -406,7 +406,7 @@ driver_alt_num( Driver * drv, int x, int num )
int y, dx;
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, num=%d", __FILE__, drv->name, x, num);
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, num=%d )", __FUNCTION__, drv->name, x, num);
if (!drv->chr)
return;
@@ -421,7 +421,7 @@ driver_alt_heartbeat( Driver * drv, int state )
{
int icon;
debug (RPT_DEBUG, "%s( drv=[%.40s], state=%d", __FILE__, drv->name, state);
debug (RPT_DEBUG, "%s( drv=[%.40s], state=%d )", __FUNCTION__, drv->name, state);
if (state == HEARTBEAT_OFF)
return;
@@ -447,7 +447,7 @@ driver_alt_icon( Driver * drv, int x, int y, int icon )
char ch1 = '?';
char ch2 = 0;
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, icon=ICON_%s", __FILE__, drv->name, x, y, widget_icon_to_iconname (icon) );
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, icon=ICON_%s )", __FUNCTION__, drv->name, x, y, widget_icon_to_iconname (icon) );
if (!drv->chr)
return;
@@ -485,17 +485,23 @@ void driver_alt_cursor( Driver * drv, int x, int y, int state )
{
/* Same question about timer in this function... */
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, state=%d", __FILE__, drv->name, x, y, state);
debug (RPT_DEBUG, "%s( drv=[%.40s], x=%d, y=%d, state=%d )", __FUNCTION__, drv->name, x, y, state);
switch( state ) {
case CURSOR_BLOCK:
case CURSOR_DEFAULT_ON:
if (timer & 2)
driver_alt_icon( drv, x, y, ICON_BLOCK_FILLED );
if (timer & 2 && drv->chr) {
if (drv->icon) {
drv->icon( drv, x, y, ICON_BLOCK_FILLED);
} else {
driver_alt_icon( drv, x, y, ICON_BLOCK_FILLED );
}
}
break;
case CURSOR_UNDER:
if (timer & 2 && drv->chr)
if (timer & 2 && drv->chr) {
drv->chr( drv, x, y, '_');
}
break;
}
+5 -2
View File
@@ -14,8 +14,11 @@
#include "drivers/lcd.h"
#define bool int
#ifndef bool
# define bool short
# define true 1
# define false 0
#endif
Driver *
driver_load( char * name, char * filename, char * args );
+22 -1
View File
@@ -13,6 +13,7 @@
#define DRIVERS_H
#include "drivers/lcd.h"
#include "shared/LL.h"
typedef struct DisplayProps {
int width, height;
@@ -21,7 +22,11 @@ typedef struct DisplayProps {
extern DisplayProps * display_props;
#define bool int
#ifndef bool
# define bool short
# define true 1
# define false 0
#endif
int
@@ -84,6 +89,9 @@ drivers_get_contrast();
void
drivers_set_contrast( int contrast );
void
drivers_cursor( int x, int y, int state );
void
drivers_backlight( int brightness );
@@ -96,4 +104,17 @@ drivers_get_key();
char
drivers_getkey();
extern LinkedList * loaded_drivers;
/* Please don't read this list except using the following functions */
static inline Driver * drivers_getfirst ()
{
return LL_GetFirst(loaded_drivers);
}
static inline Driver * drivers_getnext ()
{
return LL_GetNext(loaded_drivers);
}
#endif
+3 -4
View File
@@ -1190,12 +1190,11 @@ MtxOrb_set_char (Driver *drvthis, int n, char *dat)
MODULE_EXPORT int
MtxOrb_icon (Driver *drvthis, int x, int y, int icon)
{
return -1;
/* Does not use current icon definitions */
MtxOrb_chr (drvthis, x, y, MtxOrb_ask_bar (drvthis, icon));
return 0;
/* We return 0, however many icons are not supported
* TODO...
*/
}
/* TODO: Recover the code for I2C connectivity to MtxOrb
+4 -4
View File
@@ -600,16 +600,16 @@ curses_drv_get_key (Driver *drvthis)
return 0;
break;
case KEY_LEFT:
return "ArrowLeft";
return "Left";
break;
case KEY_UP:
return "ArrowUp";
return "Up";
break;
case KEY_DOWN:
return "ArrowDown";
return "Down";
break;
case KEY_RIGHT:
return "ArrowRight";
return "Right";
break;
case ERR:
return NULL;
-2
View File
@@ -43,8 +43,6 @@
/* Backlight data */
#define BACKLIGHT_OFF 0
#define BACKLIGHT_ON 1
#define BACKLIGHT_WARNING 2
#define BACKLIGHT_RED_ALERT 3
/* Icons. If a driver does not support an icon, it can return -1 from the
* icon function, and let the core place a replacement character.
+159 -99
View File
@@ -11,27 +11,6 @@
* Handles keypad (and other?) input from the user.
*/
/*
Currently, the keys are as follows:
Context Key Function
------- --- --------
Normal "normal" context is handled in this source file.
A Pause/Continue
B Back(Go to previous screen)
C Forward(Go to next screen)
D Open main menu
E-Z Sent to client, if any; ignored otherwise
(menu keys are not handled here, but in the menu code)
Menu
A Enter/select
B Up/Left
C Down/Right
D Exit/Cancel
E-Z Ignored
*/
#include <stdlib.h>
@@ -44,98 +23,95 @@
#include "drivers.h"
#include "client.h"
#include "clients.h"
#include "screen.h"
#include "widget.h"
#include "screenlist.h"
//#include "menus.h"
#include "menuscreens.h"
#include "input.h"
#define KeyWanted(a,b) ((a) && strchr((a), (b)))
#define CurrentScreen screenlist_current
int server_input (int key);
void input_send_to_client (Client * c, char * key);
void input_internal_key (KeyReservation * kr);
/* FIXME! The server tends to crash when "E" is pressed.. (?!)
* (but only when the joystick driver is the last one on the list...)
*/
LinkedList * keylist;
/* Checks for keypad input, and dispatches it */
int
handle_input ()
int init_input()
{
char str[15];
int key;
Screen * s;
/*Widget * w; */
Client * c;
report (RPT_INFO, "%s()", __FUNCTION__ );
report (RPT_INFO, "handle_input()" );
if ((key = drivers_getkey ()) == 0)
return 0;
debug (RPT_INFO, "handle_input got key: '%c'", key);
/* Sequence:
* Does the current screen want the key?
* IfTrue: handle and quit
* IfFalse:
* Let ALL clients handle it if they want
* Let Server handle it, too
*
* This leads to a unique situation:
* First: multiple clients may handle the same key in multiple ways
* Second: the server may handle the key differently yet
*
* Solution: Only the current screen can handle the key press.
* Alternately, only one client can handle the key press.
*/
/* TODO: Interpret and translate keys! */
/* Give current screen a shot at the key first */
s = CurrentScreen ();
if (KeyWanted(s->keys, key)) {
/* This screen wants this key. Tell it we got one */
snprintf(str, sizeof(str), "key %c\n", key);
sock_send_string(s->client->sock, str);
/* Nobody else gets this key */
}
/* if the current screen doesn't want it,
* let the server have it...
*/
else {
/* Give key to clients who want it */
c = clients_getfirst();
while (c) {
/* If the client should have this keypress... */
if(KeyWanted(c->client_keys,key)) {
/* Send keypress to client */
snprintf(str, sizeof(str), "key %c\n", key);
sock_send_string(c->sock, str);
break; /* first come, first serve */
};
c = clients_getnext();
} /* while clients */
/* Give server a shot at all keys */
server_input (key);
}
keylist = LL_new();
return 0;
}
int
handle_input ()
{
char * key;
Client * c;
KeyReservation * kr;
report (RPT_INFO, "%s()", __FUNCTION__ );
c = screenlist_current()->client;
/* Handle all keypresses */
while ((key = drivers_get_key ()) != NULL ) {
/* Find what client wants the key */
kr = input_find_key (key, c);
if (kr) {
/* A hit ! */
if (kr->client == NULL) {
report (RPT_DEBUG, "%s: key for internal client: [%.40s]", __FUNCTION__, key );
input_internal_key (kr);
}
else {
/* It's an external client */
report (RPT_DEBUG, "%s: key for external client: [%.40s]", __FUNCTION__, key );
input_send_to_client (c, key);
}
}
else {
/* What do we do with left-over keys ? */
report (RPT_INFO, "%s: left over key: [%.40s]", __FUNCTION__, key );
/* Well... nothing ! */
}
}
return 0;
}
void input_send_to_client (Client * c, char * key)
{
char * s;
debug (RPT_DEBUG, "%s( client=%p, key=\"%.40s\" )", __FUNCTION__, c, key);
/* Allocate just as much as we need */
s = malloc (strlen(key) + strlen("key \n") + 1);
sprintf(s, "key %s\n", key);
sock_send_string(c->sock, s);
free (s);
}
void
input_internal_key (KeyReservation * kr)
{
if (kr->exclusive || screenlist_current() == menuscreen) {
menuscreen_key_handler (kr->key);
}
else {
/* TODO: give keys to server screen */
}
}
/* TODO: REPLACE THE FOLLOWING FUNCTION BY SOMETHING NEW */
int
server_input (int key)
{
report(RPT_INFO, "server_input( key='%c' )", (char) key);
report(RPT_INFO, "%s( key='%c' )", __FUNCTION__, (char) key);
switch ((char) key) {
case INPUT_PAUSE_KEY:
@@ -153,14 +129,98 @@ server_input (int key)
screenlist_next ();
break;
case INPUT_MAIN_MENU_KEY:
debug (RPT_DEBUG, "got the menu key!");
debug (RPT_DEBUG, "%s: got the menu key!", __FUNCTION__);
//server_menu ();
report (RPT_ERR, "MENU TEMPORATY DISABLED");
break;
default:
debug (RPT_DEBUG, "server_input: Unused key \"%c\" (%i)", (char) key, key);
debug (RPT_DEBUG, "%s: Unused key \"%c\" (%i)", __FUNCTION__, (char) key, key);
break;
}
return 0;
}
int input_reserve_key (char * key, bool exclusive, Client * client)
{
KeyReservation * kr;
debug (RPT_DEBUG, "%s( key=\"%.40s\", exclusive=%d, client=%p )", __FUNCTION__, key, exclusive, client);
/* Find out if this key is already reserved in a way that interferes
* with the new reservation.
*/
for (kr=LL_GetFirst(keylist); kr; kr=LL_GetNext(keylist)) {
if (strcmp (kr->key, key) == 0) {
if (kr->exclusive || exclusive) {
/* Sorry ! */
return -1;
}
}
}
/* We can now safely add it ! */
kr = malloc (sizeof(KeyReservation));
kr->key = strdup (key);
kr->exclusive = exclusive;
kr->client = client;
LL_Push(keylist, kr);
report (RPT_INFO, "%s: key [%.40s] is now reserved in %s mode", __FUNCTION__, key, (exclusive?"exclusive":"shared"));
return 0;
}
void input_release_key (char * key, Client * client)
{
KeyReservation * kr;
debug (RPT_DEBUG, "%s( key=\"%.40s\", client=%p )", __FUNCTION__, key, client);
for (kr=LL_GetFirst(keylist); kr; kr=LL_GetNext(keylist)) {
if (kr->client == client
&& strcmp (kr->key, key) == 0) {
report (RPT_INFO, "%s: key [%.40s] is being released from %s mode", __FUNCTION__, key, (kr->exclusive?"exclusive":"shared"));
free (kr->key);
free (kr);
LL_DeleteNode (keylist);
return;
}
}
}
void input_release_client_keys (Client * client)
{
KeyReservation * kr;
debug (RPT_DEBUG, "%s( client=%p )", __FUNCTION__, client);
kr=LL_GetFirst(keylist);
while (kr) {
if (kr->client == client) {
report (RPT_INFO, "%s: key [%.40s] is now released from %s mode", __FUNCTION__, kr->key, (kr->exclusive?"exclusive":"shared"));
free (kr->key);
free (kr);
LL_DeleteNode (keylist);
kr = LL_Get (keylist);
} else {
kr = LL_GetNext(keylist);
}
}
}
KeyReservation * input_find_key (char * key, Client * client)
{
KeyReservation * kr;
debug (RPT_DEBUG, "%s( key=\"%.40s\", client=%p )", __FUNCTION__, key, client);
for (kr=LL_GetFirst(keylist); kr; kr=LL_GetNext(keylist)) {
if (strcmp (kr->key, key) == 0) {
if (kr->exclusive || client==kr->client) {
return kr;
}
}
}
return NULL;
}
+29
View File
@@ -12,6 +12,8 @@
#ifndef INPUT_H
#define INPUT_H
#include <stdlib.h>
/* Accepts and uses keypad input while displaying screens... */
int handle_input ();
@@ -25,5 +27,32 @@ int handle_input ();
#define INPUT_FORWARD_KEY 'C'
#define INPUT_MAIN_MENU_KEY 'D'
#ifndef bool
# define bool short
# define true 1
# define false 0
#endif
typedef struct KeyReservation {
char * key;
bool exclusive;
Client * client; /* NULL for internal clients */
} KeyReservation;
int init_input();
/* Init the input handling system */
int input_reserve_key (char * key, bool exclusive, Client * client);
/* Reserves a key for a client */
/* Return -1 if reservation of key is not possible */
void input_release_key (char * key, Client * client);
/* Releases a key reservation */
void input_release_client_keys (Client * client);
/* Releases all key reservations for a given client */
KeyReservation * input_find_key (char * key, Client * client);
/* Finds if a key reservation causes a 'hit'.
* If the key was reserved exclusively, the client will be ignored.
* If the key was reserved shared, the client must match.
*/
#endif
+4 -4
View File
@@ -46,6 +46,7 @@ extern int optind, optopt, opterr;
#include "parse.h"
#include "render.h"
#include "serverscreens.h"
#include "menuscreens.h"
#include "input.h"
#include "configfile.h"
#include "drivers.h"
@@ -211,6 +212,9 @@ main (int argc, char **argv)
}
#endif
ESSENTIAL( init_input() );
ESSENTIAL( init_menu() );
do_mainloop();
/* This loop never stops; we'll get out only with a signal...*/
@@ -292,11 +296,9 @@ process_command_line (int argc, char **argv)
case 'b':
if( strcmp( optarg, "on" ) == 0 ) {
backlight = BACKLIGHT_ON;
backlight_state = backlight;
}
else if( strcmp( optarg, "off" ) == 0 ) {
backlight = BACKLIGHT_OFF;
backlight_state = backlight;
}
else if( strcmp( optarg, "open" ) == 0 ) {
backlight = BACKLIGHT_OPEN;
@@ -398,11 +400,9 @@ process_configfile ( char *configfile )
s = config_get_string( "server", "backlight", 0, UNSET_STR );
if( strcmp( s, "on" ) == 0 ) {
backlight = BACKLIGHT_ON;
backlight_state = backlight;
}
else if( strcmp( s, "off" ) == 0 ) {
backlight = BACKLIGHT_OFF;
backlight_state = backlight;
}
else if( strcmp( s, "open" ) == 0 ) {
backlight = BACKLIGHT_OPEN;
+308 -164
View File
@@ -9,19 +9,6 @@
* 2002, Joris Robijn
*
*
* Handles server-supplied menus defined by a table. Read menu.h for
* more information.
*
* Menus are similar to "pull-down" menus, but have some extra features.
* They can contain "normal" menu items, checkboxes, sliders, "movers",
* etc..
*
* I should probably find a more elegant way of doing this in order
* to handle dynamically-changing menus such as the client list. Tcl/Tk
* has neat ways to do it. Hmm...
*
* NEW DESCRIPTION
*
* Handles a menu and all actions that can be performed on it.
*
* Menus are similar to "pull-down" menus, but have some extra features.
@@ -45,80 +32,73 @@
#include "screen.h"
/* Internal menu item drawing functions */
void menu_build_menu_screen (MenuItem *item, Screen *s);
void menu_build_slider_screen (MenuItem *item, Screen *s);
void menu_build_numeric_screen (MenuItem *item, Screen *s);
void menu_build_string_screen (MenuItem *item, Screen *s);
void menu_update_menu_screen (MenuItem *item, Screen *s);
void menu_update_slider_screen (MenuItem *item, Screen *s);
void menu_update_numeric_screen (MenuItem *item, Screen *s);
void menu_update_string_screen (MenuItem *item, Screen *s);
MenuItem *menu_create_add_item (Menu *into_menu, int type, char *id,
EventFunc(*event_func))
Menu *
menu_create (char *id, MenuEventFunc(*event_func),
char *text, void *association)
{
Menu *new_item;
Menu *new_menu;
/* Allocate space and fill struct */
new_item = malloc (sizeof(MenuItem));
if (!new_item) {
report (RPT_ERR, "menu_add_new_item: Could not allocate memory");
return NULL;
}
new_item->type = type;
new_item->id = strdup (id);
if (!new_item->id) {
report (RPT_ERR, "menu_add_new_item: Could not allocate memory");
return NULL;
}
new_item->event_func = event_func;
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", association=%p )", __FUNCTION__, id, event_func, text, association);
/* Clear the type specific data part */
memset ( &(new_item->data), 0, sizeof(new_item->data));
new_menu = menuitem_create (MENUITEM_MENU, id, event_func, text);
if (type == MENUITEM_MENU ) {
/* We have created a menu, create our needed data */
new_item->data.menu.parent = into_menu;
LL_new (new_item->data.menu.contents);
}
new_menu->data.menu.contents = LL_new();
new_menu->data.menu.association = association;
if (into_menu) {
/* Add the item to the menu */
LL_Push (into_menu->data.menu.contents, new_item);
}
return new_item;
return new_menu;
}
int menu_destroy_item (Menu *menu, MenuItem *item)
void
menu_destroy (Menu *menu)
{
/* Is the item a menu ? */
if (item->type == MENUITEM_MENU ) {
/* Check if the menu is empty */
if ( LL_Length(item->data.menu.contents) != 0 ) {
report (RPT_ERR, "menu not empty, cannot be destroyed");
return -1;
}
/* Destroy our menu data */
if (item->data.menu.text)
free (item->data.menu.text);
LL_Destroy (item->data.menu.contents);
}
free (item->id);
free (item);
debug (RPT_DEBUG, "%s( menu=\"%s\" )", __FUNCTION__, menu->id);
menu_destroy_all_items (menu);
LL_Destroy (menu->data.menu.contents);
menu->data.menu.contents = NULL;
/* After this the general menuitem routine destroys the rest... */
}
void
menu_add_item (Menu *menu, MenuItem *item)
{
debug (RPT_DEBUG, "%s( menu=\"%s\", item=\"%s\" )", __FUNCTION__, menu->id, item->id);
if (!menu) return;
/* Add the item to the menu */
LL_Push (menu->data.menu.contents, item);
item->parent = menu;
}
void
menu_remove_item (Menu *menu, MenuItem *item)
{
debug (RPT_DEBUG, "%s( menu=\"%s\", item=\"%s\" )", __FUNCTION__, menu->id, item->id);
/* Remove the item from the menu */
LL_Remove (menu->data.menu.contents, item);
}
return 0;
void
menu_destroy_all_items (Menu *menu)
{
MenuItem * item;
debug (RPT_DEBUG, "%s( menu=\"%s\" )", __FUNCTION__, menu->id);
for( item = menu_getfirst_item(menu); item; item = menu_getfirst_item(menu) ) {
menuitem_destroy (item);
LL_Remove (menu->data.menu.contents, item);
}
}
MenuItem *menu_find_item (Menu *menu, char *id)
{
MenuItem * item;
debug (RPT_DEBUG, "%s( menu=\"%s\", id=\"%s\" )", __FUNCTION__, menu->id, id);
for( item = menu_getfirst_item(menu); item; item = menu_getnext_item(menu) ) {
if ( strcmp(item->id, id) == 0 ) {
return item;
@@ -127,115 +107,279 @@ MenuItem *menu_find_item (Menu *menu, char *id)
return NULL;
}
/******** MENU SCREEN BUILD FUNCTIONS ********/
void menu_build_screen (MenuItem *item, Screen *s)
void menu_reset (Menu *menu)
{
Widget * w;
if (display_props) {
/* Nothing to build if no display size is known */
report (RPT_ERR, "menu_build_screen: display size unknown");
return;
}
/* First remove all widgets from the screen */
for ( w=screen_getfirst_widget(s); w; w=screen_getnext_widget(s) ) {
/* We know these widgets don't have subwidgets */
screen_remove_widget (s, w);
widget_destroy (w);
}
switch (item->type) {
case MENUITEM_MENU:
menu_build_menu_screen (item, s);
break;
case MENUITEM_SLIDER:
menu_build_slider_screen (item, s);
break;
case MENUITEM_NUMERIC_INPUT:
menu_build_slider_screen (item, s);
break;
case MENUITEM_STRING_INPUT:
menu_build_slider_screen (item, s);
break;
default:
report (RPT_ERR, "menu_build_screen: given menuitem cannot be active");
return;
}
menu_update_screen (item, s);
menu->data.menu.selector_pos = 0;
menu->data.menu.scroll = 0;
}
void menu_build_menu_screen (MenuItem *item, Screen *s)
void menu_build_screen (MenuItem *menu, Screen *s)
{
Widget * w;
int linenr;
MenuItem * subitem;
int itemnr;
for (linenr=1; linenr<display_props->width; linenr++) {
char buf[8];
snprintf (buf, sizeof(buf)-1, "line%d", linenr);
debug (RPT_DEBUG, "%s( menu=\"%s\", screen=\"%s\" )", __FUNCTION__, menu->id, s->id);
/* TODO: Put menu in a frame to do easy scrolling */
/* Problem: frames are not handled correctly by renderer */
/* Create menu title widget */
w = widget_create ("title", WID_TITLE, s);
screen_add_widget (s, w);
w->text = strdup(menu->text);
w->x = 1;
/* Create widgets for each subitem in the menu */
for (subitem = LL_GetFirst (menu->data.menu.contents), itemnr = 0;
subitem;
subitem = LL_GetNext (menu->data.menu.contents), itemnr ++ )
{
char buf[10];
snprintf (buf, sizeof(buf)-1, "text%d", itemnr);
buf[sizeof(buf)-1] = 0;
w = widget_create (buf, WID_STRING, s);
/* (buf will be copied) */
w->text = strdup("");
screen_add_widget (s, w);
w->x = 2;
switch (subitem->type) {
case MENUITEM_CHECKBOX:
/* Limit string length */
w->text = strdup (subitem->text);
if (strlen(subitem->text) >= display_props->width-2) {
(w->text)[display_props->width-2] = 0;
}
/* Add icon for checkbox */
snprintf (buf, sizeof(buf)-1, "icon%d", itemnr);
buf[sizeof(buf)-1] = 0;
w = widget_create (buf, WID_ICON, s);
/* (buf will be copied) */
screen_add_widget (s, w);
w->x = display_props->width - 1;
w->length = ICON_CHECKBOX_OFF;
break;
case MENUITEM_RING:
/* Create string for text + ringtext */
w->text = malloc (display_props->width);
break;
case MENUITEM_MENU:
case MENUITEM_ACTION:
case MENUITEM_SLIDER:
case MENUITEM_NUMERIC:
case MENUITEM_ALPHA:
/* Limit string length */
w->text = strdup (subitem->text);
if (strlen(subitem->text) >= display_props->width-1) {
(w->text)[display_props->width-1] = 0;
}
break;
}
}
/* Add arrow for selection on the left */
w = widget_create ("selector", WID_ICON, s);
screen_add_widget (s, w);
w->length = ICON_SELECTOR_AT_LEFT;
w->x = 1;
/* Add scrollers on the right side on top and bottom */
/* TODO: when menu is in a frame, these can be removed */
w = widget_create ("upscroller", WID_ICON, s);
screen_add_widget (s, w);
w->length = ICON_ARROW_UP;
w->x = display_props->width;
w->y = 1;
w = widget_create ("downscroller", WID_ICON, s);
screen_add_widget (s, w);
w->length = ICON_ARROW_DOWN;
w->x = display_props->width;
w->y = display_props->height;
}
void menu_update_screen (MenuItem *menu, Screen *s)
{
Widget * w;
MenuItem * subitem;
int itemnr;
debug (RPT_INFO, "%s( menu=\"%s\", screen=\"%s\" )", __FUNCTION__, menu->id, s->id);
/* Update widgets for the title */
w = screen_find_widget (s, "title");
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, "title");
w->y = 1 - menu->data.menu.scroll;
/* TODO: remove next 5 limes when rendering is safe */
if (w->y > 0 && w->y <= display_props->height) {
w->type = WID_TITLE;
} else {
w->type = WID_NONE; /* make invisible */
}
/* Update widgets for each subitem in the menu */
for (subitem = LL_GetFirst (menu->data.menu.contents), itemnr = 0;
subitem;
subitem = LL_GetNext (menu->data.menu.contents), itemnr ++ )
{
char buf[10];
char * p;
snprintf (buf, sizeof(buf)-1, "text%d", itemnr);
buf[sizeof(buf)-1] = 0;
w = screen_find_widget (s, buf);
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, buf);
w->y = 2 + itemnr - menu->data.menu.scroll;
/* TODO: remove next 5 limes when rendering is safe */
if (w->y > 0 && w->y <= display_props->height) {
w->type = WID_STRING;
} else {
w->type = WID_NONE; /* make invisible */
}
switch (subitem->type) {
case MENUITEM_CHECKBOX:
/* Update icon value for checkbox */
snprintf (buf, sizeof(buf)-1, "icon%d", itemnr);
buf[sizeof(buf)-1] = 0;
w = screen_find_widget (s, buf);
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, buf);
w->y = 2 + itemnr - menu->data.menu.scroll;
w->length = ((int[]){ICON_CHECKBOX_OFF,ICON_CHECKBOX_ON,ICON_CHECKBOX_GRAY})[subitem->data.checkbox.value];
/* TODO: remove next 5 limes when rendering is safe */
if (w->y > 0 && w->y <= display_props->height) {
w->type = WID_ICON;
} else {
w->type = WID_NONE; /* make invisible */
}
break;
case MENUITEM_RING:
/* Limit string length and add ringstring */
p = LL_GetByIndex (subitem->data.ring.strings, subitem->data.ring.value);
if (strlen(p) > display_props->width - 3) {
short a = display_props->width - 3;
/* We need to limit the ring string and DON'T
* display the item text */
strcpy (w->text, " ");
memcpy (w->text + 1, p, a);
w->text[a + 1] = 0;
}
else {
short b = display_props->width - 2 - strlen (p);
short c = min (strlen (subitem->text), b - 1);
/* We don't limit the ring string */
memset (w->text, ' ', b);
memcpy (w->text, subitem->text, c);
strcpy (w->text + b, p);
}
break;
default:
}
}
/* Update selector position */
w = screen_find_widget (s, "selector");
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, "selector");
w->y = 2 + menu->data.menu.selector_pos - menu->data.menu.scroll;
/* Enable upscroller */
w = screen_find_widget (s, "upscroller");
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, "upscroller");
if (menu->data.menu.scroll > 0) {
w->type = WID_ICON;
} else {
w->type = WID_NONE; /* disable it this way */
}
/* Enable downscroller */
w = screen_find_widget (s, "downscroller");
if (!w) report (RPT_ERR, "%s: could not find widget: %s", __FUNCTION__, "downscroller");
if (LL_Length(menu->data.menu.contents) - menu->data.menu.scroll - display_props->height + 1 > 0 ) {
w->type = WID_ICON;
} else {
w->type = WID_NONE; /* disable it this way */
}
}
void menu_build_slider_screen (MenuItem *item, Screen *s)
MenuResult menu_handle_input (Menu *menu, MenuToken token, char * key)
{
}
MenuItem *subitem;
void menu_build_numeric_screen (MenuItem *item, Screen *s)
{
}
debug (RPT_DEBUG, "%s( menu=\"%s\", token=%d, key=\"%s\" )", __FUNCTION__, menu->id, token, key);
void menu_build_string_screen (MenuItem *item, Screen *s)
{
}
void menu_build_password_screen (MenuItem *item, Screen *s)
{
}
/******** MENU SCREEN UPDATE FUNCTIONS ********/
void menu_update_screen (MenuItem *item, Screen *s) {
switch (item->type) {
case MENUITEM_MENU:
menu_update_menu_screen (item, s);
switch (token) {
case MENUTOKEN_MENU:
return MENURESULT_CLOSE;
case MENUTOKEN_ENTER:
subitem = LL_GetByIndex (menu->data.menu.contents,
menu->data.menu.selector_pos);
if (!subitem) break;
switch (subitem->type) {
case MENUITEM_ACTION:
if (subitem->event_func)
subitem->event_func (subitem, MENUEVENT_ENTER);
if (subitem->data.action.quit_menu)
return MENURESULT_QUIT;
if (subitem->data.action.close_menu)
return MENURESULT_CLOSE;
return MENURESULT_OK;
case MENUITEM_CHECKBOX:
if (subitem->data.checkbox.allow_gray) {
subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 3;
}
else {
subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 2;
}
if (subitem->event_func)
subitem->event_func (subitem, MENUEVENT_UPDATE);
return MENURESULT_OK;
case MENUITEM_RING:
subitem->data.ring.value = (subitem->data.ring.value + 1) % LL_Length (subitem->data.ring.strings);
if (subitem->event_func)
subitem->event_func (subitem, MENUEVENT_UPDATE);
return MENURESULT_OK;
case MENUITEM_MENU:
case MENUITEM_SLIDER:
case MENUITEM_NUMERIC:
case MENUITEM_ALPHA:
if (subitem->event_func)
subitem->event_func (subitem, MENUEVENT_ENTER);
return MENURESULT_ENTER;
default:
break;
case MENUITEM_SLIDER:
menu_update_slider_screen (item, s);
break;
case MENUITEM_NUMERIC_INPUT:
menu_update_slider_screen (item, s);
break;
case MENUITEM_STRING_INPUT:
menu_update_slider_screen (item, s);
break;
default:
report (RPT_ERR, "menu_update_screen: given menuitem cannot be active");
}
return MENURESULT_ERROR;
case MENUTOKEN_UP:
if (menu->data.menu.selector_pos > 0) {
menu->data.menu.selector_pos --;
if (menu->data.menu.selector_pos + 1 < menu->data.menu.scroll) {
menu->data.menu.scroll --;
}
}
else if (menu->data.menu.selector_pos == 0) {
if (menu->data.menu.selector_pos < menu->data.menu.scroll) {
menu->data.menu.scroll --;
}
}
return MENURESULT_OK;
case MENUTOKEN_DOWN:
if (menu->data.menu.selector_pos < LL_Length(menu->data.menu.contents) - 1) {
menu->data.menu.selector_pos ++;
}
if (menu->data.menu.selector_pos - menu->data.menu.scroll + 2 > display_props->height) {
menu->data.menu.scroll ++;
}
return MENURESULT_OK;
case MENUTOKEN_OTHER:
/* TODO: move to the selected number and enter it */
return MENURESULT_OK;
}
return MENURESULT_ERROR;
}
void menu_update_menu_screen (MenuItem *item, Screen *s)
{
}
void menu_update_slider_screen (MenuItem *item, Screen *s)
{
}
void menu_update_numeric_screen (MenuItem *item, Screen *s)
{
}
void menu_update_string_screen (MenuItem *item, Screen *s)
{
}
+66 -145
View File
@@ -7,186 +7,107 @@
*
* Copyright (c) 1999, William Ferrell, Scott Scriven
*
* Defines all the menu data and action.
* Defines all the menu data and actions.
*/
#ifndef MENU_H
#define MENU_H
struct MenuData;
#include "menuitem.h"
#include "shared/LL.h"
#include "screen.h"
/*********************************************************************
* Data definitions of the menustuff
* Do not modify attributes from your code, but call functions.
*/
#ifndef bool
# define bool short
# define true 1
# define false 0
#endif
typedef enum MenuItemType {
MENUITEM_NONE = 0,
MENUITEM_TITLE,
MENUITEM_MENU,
MENUITEM_ACTION,
MENUITEM_CHECKBOX,
MENUITEM_SLIDER,
MENUITEM_NUMERIC_INPUT,
MENUITEM_STRING_INPUT,
} MenuItemType;
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
typedef enum CheckboxValue {
CHECKBOX_OFF = 0, CHECKBOX_ON, CHECKBOX_GRAY
} CheckboxValue;
/* Return codes from an event value */
typedef enum MenuEventFuncResult {
MENUEVENTRES_ERROR = -1, /* Something has gone wrong */
MENUEVENTRES_OK = 0, /* Event handled OK */
MENUEVENTRES_CLOSE, /* Event handled OK, close the menu now */
MENUEVENTRES_QUIT /* Event handled OK, close ALL menus now */
} MenuEventFuncResult;
/* Events that can happen */
typedef enum MenuEventType {
MENUEVENT_SELECT, /* Item has been selected
(menu opened, action selected) */
MENUEVENT_UPDATE, /* Item has been modified
(checkbox, numeric, string, password) */
MENUEVENT_PLUS, /* Item has been modified in positive direction
(slider moved) */
MENUEVENT_MINUS /* Item has been modified in negative direction
(slider moved) */
} MenuEventType;
#define EventFunc(f) MenuEventFuncResult (f) (void *object, MenuEventType event)
typedef struct MenuItem {
int type; /* Type as defined above */
char *id; /* Internal name for client supplied menus */
EventFunc (*event_func);
/* Defines event_func to be an event function */
union data {
struct menu {
char *text; /* Visible name of the submenu */
int current_item_index; /* At what menuitem is the selector */
struct MenuItem *parent; /* Parent of this menu */
LinkedList *contents; /* What's in this menu */
} menu;
struct checkbox {
char *text; /* Visible name of item */
CheckboxValue value; /* Current value */
int allowgray; /* is CHECKBOX_GRAY allowed ? */
} checkbox;
struct slider {
char *text; /* Visible name of item */
char *lefttext; /* Text at minimal value */
char *righttext;/* Text at minimal value */
int value; /* Current value */
int minvalue;
int maxvalue;
int stepsize;
} slider;
struct numeric {
char *text; /* Visible name of item */
int value; /* Current value */
int maxvalue;
int minvalue;
} numeric;
struct string {
char *text; /* Visible name of item */
char *value; /* Current value (in a buffer) */
char passwordchar; /* For passwords */
int maxlength;
} string;
struct password {
char *text; /* Visible name of item */
char *value; /* Current value (in a buffer) */
int maxlength; /* Max allowed length */
} password;
} data;
} MenuItem;
#define Menu MenuItem
typedef MenuItem Menu;
/* A Menu is a MenuItem too.
* This definition is only for better understanding of this code.
*/
/*********************************************************************
* Functions to use the menustuff
Menu *menu_create (char *id, MenuEventFunc(*event_func),
char *text, void *association);
/* Creates a new menu.
*/
/* Creates a string value box.
* Association is free to set to anything you want. It's not used by the menu.
* Generated events: MENUEVENT_ENTER upon entering this menu,
*/
MenuItem *menu_create_add_item (Menu *into_menu, int type, char *name,
EventFunc(*event_func));
/* Creates a new item and adds it to the given menu.
* All attributes if the new item are cleared.
* into_menu What menu should it be in.
* type: type as defined above (determines also how the attributes will
* be filled).
* name: internal name of the item. Never visible. String will be
* copied.
* event_func: the event function that should be called upon actions on this
* item. see event.h.
* The data part of the new item is filled with 0's.
*
* Return value: the new item, of NULL on error.
*
* If you create a new menu, the menu data will automatically be allocated,
* and the contents pointer set to this menu.
*
* To initialize data for the data part, do things like:
*
* yourname = menu_create_add_item (m, MENUITEM_STRING_INPUT, "YourName",
* yourname_change_handler);
* yourname->data.text = strdup ("Your name");
* yourname->data.maxlength = 10;
* yourname->data.value = malloc (10+1); <--- maxlength + 1
* yourname->data.value[0] = 0; <--- clear the string
*
* The data NEEDS to be initialized immediately (at least before it's first
* used).
*
void menu_destroy (Menu *menu);
/* Deletes menu from memory.
* Destructors will be called for all subitems.
* DO NOT CALL THIS FUNCTION, CALL menuitem_destoy INSTEAD !
*/
int menu_destroy_item (Menu *menu, MenuItem *item);
/* Deletes item from menu and removes item from memory
*
* If the item is a menu, the menu data will also be deallocated.
*
* Return value: 0 for OK, -1 for error (eg. submenus not empty)
*
* To destroy the data in the data struct, do things like:
*
* free (yourname->data.value);
* free (yourname->data.text);
* menu_destroy_item (yourname);
*/
void menu_add_item (Menu *menu, MenuItem *item);
/* Adds an item to the menu */
void menu_remove_item (Menu *menu, MenuItem *item);
/* Removes an item from the menu (does not destroy it) */
void menu_destroy_all_items (Menu *menu);
/* Destroys and removes all items from the menu */
static inline MenuItem *menu_getfirst_item (Menu *menu)
/* Retrieves the first item from the list of items in the menu. */
/* Enumeration function.
* Retrieves the first item from the list of items in the menu.
*/
{
return (MenuItem*) LL_GetFirst( menu->data.menu.contents );
}
static inline MenuItem *menu_getnext_item (Menu *menu)
/* Retrieves the next item from the list of items in the menu.
/* Enumeration function.
* Retrieves the next item from the list of items in the menu.
* No other menu calls should be made between menu_first_item() and
* this function, to keep the list-cursor where it is. */
* this function, to keep the list-cursor where it is.
*/
{
return (MenuItem*) LL_GetNext( menu->data.menu.contents );
}
MenuItem *menu_find_item (Menu *menu, char *id);
/* Retrieves the first item from the list of items in the menu. */
static inline MenuItem *menu_get_current_item (Menu *menu)
/* Retrieves the current item from the list of items in the menu. */
{
return LL_GetByIndex(
menu->data.menu.contents,
menu->data.menu.selector_pos);
}
void menu_build_screen (MenuItem *item, Screen *s);
/* Builds the selected menuitem on screen using widgets
* Returns the initial state.
MenuItem *menu_find_item (Menu *menu, char *id);
/* Retrieves the first item from the list of items in the menu. */
void menu_reset (Menu *menu);
/* Resets it to initial state.
* DO NOT CALL THIS FUNCTION, CALL menuitem_build_screen INSTEAD !
*/
void menu_update_screen (MenuItem *item, Screen *s);
void menu_build_screen (Menu *menu, Screen *s);
/* Builds the selected menuitem on screen using widgets.
* DO NOT CALL THIS FUNCTION, CALL menuitem_build_screen INSTEAD !
*/
void menu_update_screen (Menu *menu, Screen *s);
/* Updates the widgets of the selected menuitem
* Returns the new state.
* DO NOT CALL THIS FUNCTION, CALL menuitem_build_screen INSTEAD !
*/
MenuResult menu_handle_input (Menu *menu, MenuToken token, char * key);
/* Does something with the given input.
* key is only used if token is MENUTOKEN_OTHER.
* DO NOT CALL THIS FUNCTION, CALL menuitem_build_screen INSTEAD !
*/
#endif
+922
View File
@@ -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;
}
+277
View File
@@ -0,0 +1,277 @@
/*
* menuitem.h
* 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
*
* Defines all the menuitem data and actions.
*
* There are a few different menuitems:
* - action
* - checkbox (on/off and optionally open)
* - slider (the user can increase/decrease a value)
* - numeric input
* - alphanumeric input (in short: alpha)
* - menu (a menu is a menuitem itself too)
*
* The slider, numeric & string input and menu have their own screen,
* that comes to front when the items are selected.
* One menuitem is in a different file: Menu data is in menu,h.
*/
#ifndef MENUITEM_H
#define MENUITEM_H
#include "shared/LL.h"
#include "screen.h"
#ifndef bool
# define bool short
# define true 1
# define false 0
#endif
#define max(a,b) (((a) > (b)) ? (a) : (b))
/*********************************************************************
* Data definitions of the menustuff
*/
#define NUM_ITEMTYPES 7
typedef enum MenuItemType { /* These values are used in the */
MENUITEM_MENU = 0, /* function tables in menuitem.c ! */
MENUITEM_ACTION = 1,
MENUITEM_CHECKBOX = 2,
MENUITEM_RING = 3,
MENUITEM_SLIDER = 4,
MENUITEM_NUMERIC = 5,
MENUITEM_ALPHA = 6,
} MenuItemType;
typedef enum CheckboxValue {
CHECKBOX_OFF = 0, CHECKBOX_ON, CHECKBOX_GRAY
} CheckboxValue;
/* Recognized input token codes */
typedef enum MenuToken {
MENUTOKEN_MENU,
MENUTOKEN_ENTER,
MENUTOKEN_UP,
MENUTOKEN_DOWN,
MENUTOKEN_OTHER
} MenuToken;
/* Return codes from an input handler */
typedef enum MenuResult {
MENURESULT_ERROR = -1, /* Something has gone wrong */
MENURESULT_OK = 0, /* Token handled OK */
MENURESULT_ENTER, /* Token handled OK, enter the selected
menuitem now */
MENURESULT_CLOSE, /* Token handled OK, close the current
menuitem now */
MENURESULT_QUIT /* Token handled OK, close ALL menus now */
} MenuResult;
/* Events caused by a menuitem */
typedef enum MenuEventType {
MENUEVENT_ENTER, /* Item has been entered
(menu opened, action chosen)
Can be used to trigger one-time update of
the items in a menu. */
MENUEVENT_UPDATE, /* Item has been modified
(checkbox, numeric, alphanumeric) */
MENUEVENT_PLUS, /* Item has been modified in positive direction
(slider moved) */
MENUEVENT_MINUS /* Item has been modified in negative direction
(slider moved) */
} MenuEventType;
#define MenuEventFunc(f) int (f) (struct MenuItem *item, MenuEventType event)
/* I've used a union in the struct below. Why? And why not for Widget?
*
* There are different types of menuitems. There are also types of widgets.
* Menuitems have, just like widgets, different datafields per subtype.
* The difference is that menuitems have, unlike widgets _many__different_
* attributes. Widgets share many attributes like x, y, text.
* The code would become unreadable if we used the 'widget way', or it would
* get large if we define datafields that we use for only one type of
* menuitem. (Joris)
*/
typedef struct MenuItem {
MenuItemType type; /* Type as defined above */
char *id; /* Internal name for client supplied menus */
struct MenuItem *parent; /* Parent of this menuitem */
MenuEventFunc (*event_func);
/* Defines event_func to be an event function */
char *text; /* Visible name of the item */
union data {
struct menu {
int selector_pos; /* At what menuitem is the
selector (0 for first) */
int scroll; /* How much has the menu been
scrolled down */
void *association; /* To associate an object
with this menu */
LinkedList *contents; /* What's in this menu */
} menu;
struct action {
bool close_menu; /* Close active menu ? */
bool quit_menu; /* Close entire menu ? */
} action;
struct checkbox {
bool allow_gray; /* Is CHECKBOX_GRAY allowed ? */
CheckboxValue value; /* Current value */
} checkbox;
struct ring {
LinkedList *strings; /* The selectable strings */
int value; /* Current index */
} ring;
struct slider {
char *mintext; /* Text at minimal value */
char *maxtext; /* Text at minimal value */
int minvalue;
int maxvalue;
int stepsize;
int value; /* Current value */
} slider;
struct numeric {
int maxvalue;
int minvalue;
short allowed_decimals; /* Number of numbers behind dot */
int value; /* Current value */
char *edit_str; /* Value while being edited */
short edit_pos; /* Position while editing */
short error_code;
} numeric;
struct alpha {
char password_char; /* For passwords */
short minlength;
short maxlength;
char *allowed_chars; /* Allowed characters */
char *value; /* Current value */
char *edit_str; /* Value while being edited */
short edit_pos; /* Position while editing */
short error_code;
} alpha;
} data;
} MenuItem;
/*********************************************************************
* Functions to use the menustuff
*/
MenuItem *menuitem_create (MenuItemType type, char *id,
MenuEventFunc(*event_func), char *text);
/* YOU SHOULD NOT CALL THIS FUNCTION BUT THE TYPE SPECIFIC ONE INSTEAD */
/* For all constructor functions below the following:
*
* id: internal name of the item. Never visible. String will be
* copied.
* event_func: the event function that should be called upon actions on this
* item. see event.h.
* text: the displayed text.
*
* All strings will be copied !
*
* Return value: the new item, of NULL on error.
*
* To create a Menu (which is also an ItemType), call menu_create.
*
*/
MenuItem *menuitem_create_action (char *id, MenuEventFunc(*event_func),
char *text, bool close_menu, bool quit_menu);
/* Creates a an action item (a string only).
* Generated events: MENUEVENT_ENTER when user selects the item.
*/
MenuItem *menuitem_create_checkbox (char *id, MenuEventFunc(*event_func),
char *text, bool allow_gray, bool value);
/* Creates a checkbox.
* Generated events: MENUEVENT_UPDATE when user changes value (immediately).
*/
MenuItem *menuitem_create_ring (char *id, MenuEventFunc(*event_func),
char *text, char *strings, short value);
/* Creates a ring with the given string, separated by tabs.
* value is the (initial) index in the strings.
* eg: if strings="abc\tdef" the value=1 means that "def" is selected.
* Generated events: MENUEVENT_UPDATE when user changes value (immediately).
*/
MenuItem *menuitem_create_slider (char *id, MenuEventFunc(*event_func),
char *text, char *mintext, char *maxtext,
int minvalue, int maxvalue, int stepsize, int value);
/* Creates a slider with the given min and max values.
* If the display is big enough the mintext and maxtext will be placed
* at the end positions of the slider.
* You can set the step size. Make it 0 to disable the automatic value chaning,
* and update the value yourself.
* Generated events: MENUEVENT_ENTER upon entering this item,
* MENUEVENT_PLUS, MENUEVENT_MINUS when slider is moved (immediately).
*/
MenuItem *menuitem_create_numeric (char *id, MenuEventFunc(*event_func),
char *text, int minvalue, int maxvalue, int value);
/* Creates a numeric value box.
* Value can range from minvalue to maxvalue.
* Generated events: MENUEVENT_ENTER upon entering this item,
* MENUEVENT_UPDATE when user finishes the value (no immediate update).
*/
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);
/* Creates a string value box.
* Value should have given minimal and maximal length. You can set whether
* caps, non-caps and numbers are allowed. Also you can alow other characters.
* If password char is non-zero, you will only see this char, not the actual
* input.
* Generated events: MENUEVENT_ENTER upon entering this item,
* MENUEVENT_UPDATE when user finishes the value (no immediate update).
*/
void menuitem_destroy (MenuItem *item);
/* Deletes item from memory.
* All allocated extra data (like strings) will be freed.
*/
static inline MenuItem *menuitem_get_parent (MenuItem *item)
{
return item->parent;
}
void menuitem_reset (MenuItem *item);
/* Resets the item to the initial state.
* You should call menuitem_update after this to see the effects.
* This call is useless on items that have immediate effect, like a slider.
* Those items do not keep temporary data.
*/
void menuitem_build_screen (MenuItem *item, Screen *s);
/* Builds the selected menuitem on screen using widgets.
* Should be re-called if menuitem data has been changed.
* There are a few (logical) exceptions to this:
* - the values
* - the menu scroll and menu index
*/
void menuitem_update_screen (MenuItem *item, Screen *s);
/* Updates the widgets of the selected menuitem
* Fills all widget attributes with the corrrect values.
*/
MenuResult menuitem_handle_input (MenuItem *item, MenuToken token, char * key);
/* Does something with the given input.
* key is only used if token is MENUTOKEN_OTHER.
*/
#endif
+345 -2
View File
@@ -9,11 +9,354 @@
* 2002, Joris Robijn
*
*
* Creates the server menu screen (s).
* Handles the keypresses for this screen.
* Creates the server menu screen(s) and creates the menus that should be
* displayed on this screen.
* It also handles its keypresses and converts them to menu tokens for
* easier processing.
*
* NOTE: menuscreens.c does not know whether a menuitem is displayed INSIDE
* a menu or on a separate SCREEN, for flexibility.
*
*/
#include <string.h>
#include <unistd.h>
#include "screen.h"
#include "screenlist.h"
#include "menuscreens.h"
#include "configfile.h"
#include "shared/report.h"
#include "input.h"
#include "driver.h"
#include "drivers.h"
/* Next include files are needed for settings that we can modify */
#include "render.h"
char * menu_key;
char * enter_key;
char * up_key;
char * down_key;
Screen * menuscreen;
MenuItem * active_menuitem;
Menu * main_menu;
Menu * screens_menu;
void menuscreen_create_menu ();
MenuEventFunc (menuscreen_heartbeat);
MenuEventFunc (menuscreen_backlight);
MenuEventFunc (menuscreen_contrast);
MenuEventFunc (menuscreen_brightness);
MenuEventFunc (menuscreen_screens);
int init_menu()
{
active_menuitem = NULL;
debug (RPT_DEBUG, "%s()", __FUNCTION__);
/* Get keys from config file */
menu_key = strdup (config_get_string ("menu", "MenuKey", 0, "Menu"));
enter_key = strdup (config_get_string ("menu", "EnterKey", 0, "Enter"));
up_key = strdup (config_get_string ("menu", "UpKey", 0, "Up"));
down_key = strdup (config_get_string ("menu", "DownKey", 0, "Down"));
/* Now reserve keys */
input_reserve_key (menu_key, true, NULL);
input_reserve_key (enter_key, false, NULL);
input_reserve_key (up_key, false, NULL);
input_reserve_key (down_key, false, NULL);
/* Create screen */
menuscreen = screen_create ("_menu_screen", NULL);
/* Build menu */
menuscreen_create_menu ();
return 0;
}
bool is_menu_key (char * key)
{
if (strcmp (key, menu_key) == 0)
return true;
else
return false;
}
void menuscreen_key_handler (char *key)
{
char token = 0;
MenuResult res;
debug (RPT_DEBUG, "%s( \"%s\" )", __FUNCTION__, key);
if (strcmp (key, menu_key) == 0) {
token = MENUTOKEN_MENU;
}
else if (strcmp (key, enter_key) == 0) {
token = MENUTOKEN_ENTER;
}
else if (strcmp (key, up_key) == 0) {
token = MENUTOKEN_UP;
}
else if (strcmp (key, down_key) == 0) {
token = MENUTOKEN_DOWN;
}
else {
token = MENUTOKEN_OTHER;
}
/* Is the menu already active ? */
if (!active_menuitem) {
debug (RPT_DEBUG, "%s: Activating menu screen", __FUNCTION__);
active_menuitem = main_menu;
menuitem_build_screen (active_menuitem, menuscreen);
menuitem_reset (active_menuitem);
menuitem_update_screen (active_menuitem, menuscreen);
if (screenlist_add (menuscreen) < 0) {
report (RPT_ERR, "%s: Error queueing menu screen", __FUNCTION__);
}
/* TODO: raise it ! */
return;
}
res = menuitem_handle_input (active_menuitem, token, key);
switch (res) {
case MENURESULT_ERROR:
report (RPT_ERR, "%s: Error from menu_handle_input", __FUNCTION__);
break;
case MENURESULT_OK:
/* Nothing extra to be done */
break;
case MENURESULT_ENTER:
/* Enter the selected menuitem
* Note: this is not for checkboxes etc that don't have their
* own screen. The menu_handle_input function should do
* things like toggling checkboxes !
*/
debug (RPT_DEBUG, "%s: Entering subitem", __FUNCTION__);
active_menuitem = menu_get_current_item (active_menuitem);
menuitem_build_screen (active_menuitem, menuscreen);
menuitem_reset (active_menuitem);
break;
case MENURESULT_CLOSE:
debug (RPT_DEBUG, "%s: Closing item", __FUNCTION__);
active_menuitem = menuitem_get_parent (active_menuitem);
if (active_menuitem) {
/* We were in at least second level menu */
menuitem_build_screen (active_menuitem, menuscreen);
break;
}
/* If first level menu, quit menu now
* Therefor no break; now.
*/
case MENURESULT_QUIT:
debug (RPT_DEBUG, "%s: Closing menu screen", __FUNCTION__);
active_menuitem = NULL;
/* TODO: send menu to backgr */
if (screenlist_remove (menuscreen) < 0) {
report (RPT_ERR, "%s: Error unqueueing menu screen", __FUNCTION__);
}
break;
}
if (active_menuitem) {
menuitem_update_screen (active_menuitem, menuscreen);
}
}
void menuscreen_create_menu ()
{
Menu * options_menu;
Menu * driver_menu;
MenuItem * checkbox;
MenuItem * slider;
Driver * driver;
MenuItem * test_item;
Menu * test_menu;
debug (RPT_DEBUG, "%s()", __FUNCTION__);
main_menu = menu_create ("mainmenu", NULL, "LCDproc Menu", NULL);
options_menu = menu_create ("options", NULL, "Options", NULL);
menu_add_item (main_menu, options_menu);
screens_menu = menu_create ("screens", menuscreen_screens, "Screens", NULL);
menu_add_item (main_menu, screens_menu);
checkbox = menuitem_create_checkbox ("heartbeat", menuscreen_heartbeat, "Heartbeat", true, heartbeat);
menu_add_item (options_menu, checkbox);
checkbox = menuitem_create_checkbox ("backlight", menuscreen_backlight, "Backlight", true, backlight);
menu_add_item (options_menu, checkbox);
for (driver = drivers_getfirst(); driver; driver = drivers_getnext()) {
int contrast_avail = 0;
int brightness_avail = 0;
contrast_avail = (driver->get_contrast && driver->set_contrast);
brightness_avail = (driver->get_brightness && driver->set_brightness);
if (contrast_avail || brightness_avail) {
driver_menu = menu_create (driver->name, NULL, driver->name, driver);
menu_add_item (options_menu, driver_menu);
if (contrast_avail) {
slider = menuitem_create_slider ("contrast", menuscreen_contrast, "Contrast", "min", "max", 0, 1000, 100, 500);
menu_add_item (driver_menu, slider);
}
if (brightness_avail) {
slider = menuitem_create_slider ("onbrightness", menuscreen_brightness, "On Brightness", "min", "max", 0, 1000, 100, 500);
menu_add_item (driver_menu, slider);
slider = menuitem_create_slider ("offbrightness", menuscreen_brightness, "Off Brightness", "min", "max", 0, 1000, 100, 500);
menu_add_item (driver_menu, slider);
}
}
}
test_menu = menu_create ("test", NULL, "Test menu", NULL);
menu_add_item (main_menu, test_menu);
test_item = menuitem_create_action ("", NULL, "Action", false, false);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_action ("", NULL, "Action,closing", true, false);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_action ("", NULL, "Action,quiting", true, true);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_checkbox ("", NULL, "Checkbox", false, false);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_checkbox ("", NULL, "Checkbox, gray", true, false);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_ring ("", NULL, "Ring", "ABC\tDEF\t01234567890\tOr a very long string that will not fit on any display", 1);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_slider ("", NULL, "Slider", "mintext", "maxtext", -20, 20, 1, 0);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_slider ("", NULL, "Slider,step=5", "mintext", "maxtext", -20, 20, 5, 0);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_numeric ("", NULL, "Numeric", 1, 365, 15);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_numeric ("", NULL, "Numeric,signed", -20, +20, 15);
menu_add_item (test_menu, test_item);
test_item = menuitem_create_alpha ("", NULL, "Alpha", 0, 3, 12, true, true, true, ".-+@", "LCDproc-v0.5");
menu_add_item (test_menu, test_item);
test_item = menuitem_create_alpha ("", NULL, "Alpha, caps only", 0, 3, 12, true, false, false, "-", "LCDPROC");
menu_add_item (test_menu, test_item);
}
MenuEventFunc (menuscreen_heartbeat)
{
debug (RPT_DEBUG, "%s( item=%s, event=%d )", __FUNCTION__, item->id, event);
if (event == MENUEVENT_UPDATE) {
/* Set heartbeat setting */
heartbeat = item->data.checkbox.value;
report (RPT_INFO, "Menu: set heartbeat to %d",
item->data.checkbox.value);
}
return 0;
}
MenuEventFunc (menuscreen_backlight)
{
debug (RPT_DEBUG, "%s( item=%s, event=%d )", __FUNCTION__, item->id, event);
if (event == MENUEVENT_UPDATE)
{
/* Set backlight setting */
backlight = item->data.checkbox.value;
report (RPT_INFO, "Menu: set backlight to %d",
item->data.checkbox.value);
}
return 0;
}
MenuEventFunc (menuscreen_contrast)
{
debug (RPT_DEBUG, "%s( item=%s, event=%d )", __FUNCTION__, item->id, event);
/* This function can be called by one of several drivers that
* support contrast !
* We need to check the menu association to see which driver. */
if (event == MENUEVENT_MINUS || event == MENUEVENT_PLUS) {
/* Determinte the driver */
Driver * driver = item->parent->data.menu.association;
driver->set_contrast (driver, item->data.slider.value);
//item->data.slider.value = driver->get_contrast (driver);
report (RPT_INFO, "Menu: set contrast of [%.40s] to %d",
item->data.checkbox.value);
}
return 0;
}
MenuEventFunc (menuscreen_brightness)
{
debug (RPT_DEBUG, "%s( item=%s, event=%d )", __FUNCTION__, item->id, event);
/* This function can be called by one of several drivers that
* support contrast !
* We need to check the menu association to see which driver. */
if (event == MENUEVENT_MINUS || event == MENUEVENT_PLUS) {
/* Determinte the driver */
Driver * driver = item->parent->data.menu.association;
if ( strcmp (item->id, "onbrightness") == 0) {
driver->set_brightness (driver, BACKLIGHT_ON, item->data.slider.value);
}
else if ( strcmp (item->id, "offbrightness") == 0) {
driver->set_brightness (driver, BACKLIGHT_OFF, item->data.slider.value);
}
}
return 0;
}
MenuEventFunc (menuscreen_screens)
{
debug (RPT_DEBUG, "%s( item=%s, event=%d )", __FUNCTION__, item->id, event);
if (event == MENUEVENT_ENTER) {
/* We are entering this menu */
Screen * s;
Menu * m;
MenuItem * mi;
/* Clean the screens menu */
menu_destroy_all_items (screens_menu);
/* Read list of screens */
for (s = LL_GetFirst(screenlist_getlist()); s; s = LL_GetNext(screenlist_getlist())) {
/* TODO: don't display screens that have _ at start of id */
m = menu_create (s->id, NULL, s->name?s->name:s->id, s);
menu_add_item (screens_menu, m);
mi = menuitem_create_action ("", NULL, "To Front", true, true);
menu_add_item (m, mi);
mi = menuitem_create_checkbox ("", NULL, "Visible", false, true);
menu_add_item (m, mi);
mi = menuitem_create_numeric ("", NULL, "Duration", 2, 3600, s->duration);
menu_add_item (m, mi);
mi = menuitem_create_numeric ("", NULL, "Priority", -1, 4, s->priority);
menu_add_item (m, mi);
}
}
return 0;
}
+13 -2
View File
@@ -15,9 +15,20 @@
#define MENUSCREENS_H
#include "menu.h"
#include "screen.h"
MenuEventFuncResult menuscreen_key_handler ();
/* This handler should be called by the real handler for the event */
extern Screen * menuscreen;
int init_menu();
bool is_menu_key (char * key);
/* This function indicates to the input part whether this key was the
* reserved menu key.
*/
void menuscreen_key_handler (char *key);
/* This handler handles the keypresses for the menu.
*/
#endif
+54 -71
View File
@@ -39,8 +39,9 @@
#include "render.h"
int heartbeat = HEARTBEAT_OPEN;
int heartbeat_fallback = HEARTBEAT_ON; /* If no heartbeat setting has been set at all */
int backlight = BACKLIGHT_OPEN;
int backlight_state = BACKLIGHT_OPEN;
int backlight_fallback = BACKLIGHT_ON; /* If no backlight setting has been set at all */
int backlight_brightness = 255;
int backlight_off_brightness = 0;
int output_state = 0;
@@ -55,9 +56,9 @@ int
draw_screen (Screen * s, int timer)
{
static Screen * old_s = NULL;
int tmp = 0, tmp_state = 0;
int tmp_state = 0;
report(RPT_INFO, "draw_screen( screen=\"%.40s\", timer=%d ) ==== START RENDERING ====", s->name, timer );
report(RPT_INFO, "draw_screen( screen=\"%.40s\", timer=%d ) ==== START RENDERING ====", s->id, timer );
reset = 1;
@@ -73,52 +74,41 @@ draw_screen (Screen * s, int timer)
/* FIXME drivers_backlight --
*
* This should be in a separate function altogether.
* Perhaps several: drivers_backlight_off, drivers_backlight_on,
* drivers_backlight_brightness, drivers_backlight_flash ...
*
* If the screen's backlight_state isn't set (default) then we
* If the screen's backlight isn't set (default) then we
* inherit the backlight state from the parent client. This allows
* the client to override it's childrens settings.
* The server can also override the clients and screens settings.
*/
if (s->backlight == BACKLIGHT_OPEN) {
if (s->client) tmp_state = s->client->backlight;
} else {
if (backlight != BACKLIGHT_OPEN) {
tmp_state = backlight;
} else if (s->client && s->client->backlight != BACKLIGHT_OPEN) {
tmp_state = s->client->backlight;
} else if (s->backlight != BACKLIGHT_OPEN) {
tmp_state = s->backlight;
} else {
tmp_state = backlight_fallback;
}
/* Set up backlight to the correct state... */
/* NOTE: dirty stripping of other options... */
switch (tmp_state & 1) {
case BACKLIGHT_OFF:
drivers_backlight (BACKLIGHT_OFF);
break;
/* Backlight on (easy) */
case BACKLIGHT_ON:
drivers_backlight (BACKLIGHT_ON);
break;
default:
/* Backlight flash: check timer and flip backlight as appropriate */
if (tmp_state & BACKLIGHT_FLASH) {
tmp = (!((timer & 7) == 7));
if (tmp_state & 1)
drivers_backlight (tmp ? backlight_brightness : backlight_off_brightness);
/*drivers_backlight(backlight_brightness * (!((timer&7) == 7))); */
else
drivers_backlight (!tmp ? backlight_brightness : backlight_off_brightness);
/*drivers_backlight(backlight_brightness * ((timer&7) == 7)); */
/* Backlight blink: check timer and flip backlight as appropriate */
} else if (tmp_state & BACKLIGHT_BLINK) {
tmp = (!((timer & 14) == 14));
if (tmp_state & 1)
drivers_backlight (tmp ? backlight_brightness : backlight_off_brightness);
/*drivers_backlight(backlight_brightness * (!((timer&14) == 14))); */
else
drivers_backlight (!tmp ? backlight_brightness : backlight_off_brightness);
/*drivers_backlight(backlight_brightness * ((timer&14) == 14)); */
}
break;
/* Backlight flash: check timer and flip backlight as appropriate */
if (tmp_state & BACKLIGHT_FLASH) {
drivers_backlight (
(
(tmp_state & BACKLIGHT_ON)
^ ((timer & 7) == 7)
) ? BACKLIGHT_ON : BACKLIGHT_OFF );
/* Backlight blink: check timer and flip backlight as appropriate */
}
else if (tmp_state & BACKLIGHT_BLINK) {
drivers_backlight (
(
(tmp_state & BACKLIGHT_ON)
^ ((timer & 14) == 14)
) ? BACKLIGHT_ON : BACKLIGHT_OFF );
} else {
/* Simple: Only send lowest bit then...*/
drivers_backlight (tmp_state & BACKLIGHT_ON);
}
/* Output ports from LCD - outputs depend on the current screen */
@@ -127,24 +117,21 @@ draw_screen (Screen * s, int timer)
/* Draw a frame... */
draw_frame (s->widgetlist, 'v', 0, 0, display_props->width, display_props->height, s->width, s->height, (((s->duration / s->height) < 1) ? 1 : (s->duration / s->height)), timer);
/* Set the cursor */
drivers_cursor (s->cursor_x, s->cursor_y, s->cursor);
/*debug(RPT_DEBUG, "draw_screen done"); */
if (heartbeat) {
drivers_heartbeat(s->heartbeat);
/*if ((s->heartbeat == HEART_ON) || heartbeat == HEART_ON) { */
/* Set this to pulsate like a real heart beat... */
/* (binary is fun... :) */
/* drivers_heartbeat (); */
/*drivers_icon (!((timer + 4) & 5), 0); */
/*drivers_chr (display_props->width, 1, 0); */
/*} */
/* else */
/* This seems unnecessary... heartbeat is nicer... */
/* if ((s->heartbeat == HEART_OPEN) && heartbeat != HEART_OFF) { */
/* char *phases = "-\\|/"; */
/* drivers_chr (ldisplay_props->width, 1, phases[timer & 3]); */
/* } */
if (heartbeat != HEARTBEAT_OPEN) {
tmp_state = heartbeat;
} else if (s->client && s->client->heartbeat != HEARTBEAT_OPEN) {
tmp_state = s->client->heartbeat;
} else if (s->heartbeat != HEARTBEAT_OPEN) {
tmp_state = s->heartbeat;
} else {
tmp_state = heartbeat_fallback;
}
drivers_heartbeat(tmp_state);
/* flush display out, frame and all... */
drivers_flush ();
@@ -307,7 +294,7 @@ draw_frame (LinkedList * list,
break;
case WID_ICON:
drivers_icon (w->x, w->y, w->length);
break;
case WID_TITLE: /* FIXME: Doesn't work quite right in frames...*/
if (!w->text)
@@ -316,14 +303,12 @@ draw_frame (LinkedList * list,
break;
drivers_icon (w->x + left, w->y + top, ICON_BLOCK_FILLED);
drivers_icon (w->x + 1 + left, w->y + top, ICON_BLOCK_FILLED);
drivers_icon (w->x + left + 1, w->y + top, ICON_BLOCK_FILLED);
str[0] = ' ';
length = strlen (w->text);
if (length <= vis_width - 6) {
memcpy (str + 1, w->text, length);
str[length + 1] = ' ';
x = length + 4;
strcpy (str, w->text);
x = length + 5;
} else /* Scroll the title, if it doesn't fit...*/
{
speed = 1;
@@ -339,7 +324,6 @@ draw_frame (LinkedList * list,
screenlist_action = 0;
}
x %= (length);
x -= 3;
if (x < 0)
x = 0;
if (x > length - (vis_width - 6))
@@ -349,18 +333,17 @@ draw_frame (LinkedList * list,
{
x = (length - (vis_width - 6)) - x;
}
strncpy (str + 1, w->text + x, (vis_width - 6));
str[vis_width - 5] = ' ';
x = vis_width - 2;
strncpy (str, w->text + x, (vis_width - 6));
x = vis_width - 1;
str[vis_width-6] = 0;
}
str[vis_width-4] = 0;
drivers_string (w->x + 2 + left, w->y + top, str);
drivers_string (w->x + 3 + left, w->y + top, str);
for (; x<vis_width; x++) {
drivers_icon (w->x + x + left, w->y + top, ICON_BLOCK_FILLED);
for (; x<=vis_width; x++) {
drivers_icon (w->x + x - 1 + left, w->y + top, ICON_BLOCK_FILLED);
}
break;
case WID_SCROLLER: /* FIXME: doesn't work in frames...*/
{
-1
View File
@@ -36,7 +36,6 @@
extern int heartbeat;
extern int backlight;
extern int backlight_state;
extern int backlight_brightness;
extern int backlight_off_brightness;
extern int output_state;
+3
View File
@@ -65,6 +65,9 @@ screen_create (char * id, Client * client)
s->timeout = default_timeout; /*ignored unless greater than 0.*/
s->backlight = BACKLIGHT_OPEN; /*Lets the screen do it's own*/
/*or do what the client says.*/
s->cursor = CURSOR_OFF;
s->cursor_x = 1;
s->cursor_y = 1;
s->widgetlist = LL_new ();
if (!s->widgetlist) {
+14 -53
View File
@@ -36,8 +36,6 @@ char one[256] = "";
char two[256] = "";
char three[256] = "";
#define WidgetString(w,a,b,t) {(w)->x=(a);(w)->y=(b);(w)->text=(t);}
int
server_screen_init ()
{
@@ -69,25 +67,23 @@ server_screen_init ()
}
/* Now, initialize all the widgets...*/
if ((w = screen_find_widget (server_screen, "title")) != NULL) {
w->text = title;
} else
report (RPT_ERR, "server_screen_init: Can't find title");
w = screen_find_widget (server_screen, "title");
w->text = strdup (title);
if ((w = screen_find_widget (server_screen, "one")) != NULL)
WidgetString(w,1,2,one)
else
report (RPT_ERR, "server_screen_init: Can't find widget one");
w = screen_find_widget (server_screen, "one");
w->x = 1;
w->y = 2;
w->text = strdup (one);
if ((w = screen_find_widget (server_screen, "two")) != NULL)
WidgetString(w,1,3,two)
else
report (RPT_ERR, "server_screen_init: Can't find widget two");
w = screen_find_widget (server_screen, "two");
w->x = 1;
w->y = 3;
w->text = strdup (two);
if ((w = screen_find_widget (server_screen, "three")) != NULL)
WidgetString(w,1,4,three)
else
report (RPT_ERR, "server_screen_init: Can't find widget three");
w = screen_find_widget (server_screen, "three");
w->x = 1;
w->y = 4;
w->text = strdup (three);
/* And enqueue the screen*/
screenlist_add (server_screen);
@@ -97,20 +93,6 @@ server_screen_init ()
return 0;
}
static int
screen_count (Client * c) {
int n;
n = 0;
LL_Rewind (c->screenlist);
do {
if (LL_Get (c->screenlist) != NULL)
n++;
} while (LL_Next (c->screenlist) == 0);
return n;
}
int
update_server_screen (int timer)
{
@@ -131,27 +113,6 @@ update_server_screen (int timer)
num_screens += client_screen_count(c);
}
/*
if (c) {
num_clients++;
num_screens += client_screen_count(c);
num_screens += screen_count(c);
*/
/* LL_Rewind (c->data->screenlist); */
/* do { */
/* s = LL_Get (c->data->screenlist); */
/* if (s) { */
/* num_screens++; */
/* } */
/* } while (LL_Next (c->data->screenlist) == 0); */
/*
}
}
*/
/* Format strings for the appropriate size display... */
if (display_props->height >= 3) {
snprintf (one, sizeof(one), "Clients: %i", num_clients);
+4
View File
@@ -269,6 +269,10 @@ sock_close_all ()
{
int fd;
return 0;
/* Do we need to do this ? Clients_shutdown already closes all
client connections ... */
report (RPT_INFO, "sock_close_all()");
for (fd = 0; fd < FD_SETSIZE; fd++) {
+2 -11
View File
@@ -6,9 +6,10 @@
* COPYING file distributed with this package.
*
* Copyright (c) 1999, William Ferrell, Scott Scriven
* 2002, Joris Robijn
*
*
* Does widget management
* Does all actions on widgets
*
*/
@@ -65,9 +66,6 @@ struct icontable {
{0,NULL}
};
//static widget *widget_finder (LinkedList * list, char *id);
//static int widget_remover (LinkedList * list, widget * w);
Widget *
widget_create (char *id, WidgetType type, Screen * screen)
@@ -128,14 +126,8 @@ widget_destroy (Widget * w)
if (w->id)
free (w->id);
/*debug(RPT_DEBUG, "widget_destroy: id...");*/
if (w->text)
free (w->text);
/*debug(RPT_DEBUG, "widget_destroy: text...");*/
if (w->type == WID_FRAME) {
/* TODO: create a screen for the frame widget */
}
/* Free subscreen of frame widget too */
if (w->type == WID_FRAME) {
@@ -143,7 +135,6 @@ widget_destroy (Widget * w)
}
free (w);
/*debug(RPT_DEBUG, "widget_destroy: widget...");*/
return 0;
}
+24
View File
@@ -743,6 +743,30 @@ LL_Find (LinkedList * list, int compare (void *, void *), void *value)
return NULL;
}
//////////////////////////////////////////////////////////////////////
// Array like...
// Goes to the nth list item, and returns the
// data found there.
//
void *
LL_GetByIndex (LinkedList * list, int index)
{
LL_node *node;
int num = 0;
if (!list)
return NULL;
if (index<0)
return NULL;
for (node = list->head.next; node != &list->tail; node = node->next) {
if (num == index)
return node->data;
num ++;
}
return NULL; // got past the end
}
//////////////////////////////////////////////////////////////////////
// Sorts the list, then rewinds it...
//
+7 -4
View File
@@ -30,7 +30,7 @@
For errors, the general convention is that "0" means success, and
a negative number means failure. Check LL.c to be sure, though.
*******************************************************************
To change the data, try this:
@@ -73,12 +73,12 @@
my_data = (my_data *)LL_Get(list);
... do something to it ...
} while(LL_Next(list) == 0);
*******************************************************************
You can also treat the list like a stack, or a queue. Just use the
following functions:
LL_Push() // Regular stack stuff: add, remove, peek, rotate
LL_Pop()
LL_Top()
@@ -191,6 +191,9 @@ int LL_Length (LinkedList * list); // Returns # of nodes in entire list
// Searching...
void *LL_Find (LinkedList * list, int compare (void *, void *), void *value);
// Array operation...
void *LL_GetByIndex (LinkedList * list, int index); // gets the nth node, 0 being the first
// Sorts the list...
int LL_Sort (LinkedList * list, int compare (void *, void *));