Menustuff added/modified!
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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...*/
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 *));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user