mirror of
https://github.com/ipxe/ipxe
synced 2025-12-20 12:00:19 +03:00
[dynui] Generalise the concept of a menu to a dynamic user interface
We currently have an abstract model of a dynamic menu as a list of
items, each of which has a name, a description, and assorted metadata
such as a shortcut key. The "menu" and "item" commands construct
representations in this abstract model, and the "choose" command then
presents the items as a single-choice menu, with the selected item's
name used as the output value.
This same abstraction may be used to model a dynamic form as a list of
editable items, each of which has a corresponding setting name, an
optional description label, and assorted metadata such as a shortcut
key. By defining a "form" command as an alias for the "menu" command,
we could construct and present forms using commands such as:
#!ipxe
form Login to ${url}
item username Username or email address
item --secret password Password
present
or
#!ipxe
form Configure IPv4 networking for ${netX/ifname}
item netX/ip IPv4 address
item netX/netmask Subnet mask
item netX/gateway Gateway address
item netX/dns DNS server address
present
Reusing the same abstract model for both menus and forms allows us to
minimise the increase in code size, since the implementation of the
"form" and "item" commands is essentially zero-cost.
Rename everything within the abstract data model from "menu" to
"dynamic user interface" to reflect this generalisation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
182
src/core/dynui.c
Normal file
182
src/core/dynui.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Dynamic user interfaces
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/dynui.h>
|
||||
|
||||
/** List of all dynamic user interfaces */
|
||||
static LIST_HEAD ( dynamic_uis );
|
||||
|
||||
/**
|
||||
* Create dynamic user interface
|
||||
*
|
||||
* @v name User interface name, or NULL
|
||||
* @v title User interface title, or NULL
|
||||
* @ret dynui Dynamic user interface, or NULL on failure
|
||||
*/
|
||||
struct dynamic_ui * create_dynui ( const char *name, const char *title ) {
|
||||
struct dynamic_ui *dynui;
|
||||
size_t name_len;
|
||||
size_t title_len;
|
||||
size_t len;
|
||||
char *name_copy;
|
||||
char *title_copy;
|
||||
|
||||
/* Destroy any existing user interface of this name */
|
||||
dynui = find_dynui ( name );
|
||||
if ( dynui )
|
||||
destroy_dynui ( dynui );
|
||||
|
||||
/* Use empty title if none given */
|
||||
if ( ! title )
|
||||
title = "";
|
||||
|
||||
/* Allocate user interface */
|
||||
name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
|
||||
title_len = ( strlen ( title ) + 1 /* NUL */ );
|
||||
len = ( sizeof ( *dynui ) + name_len + title_len );
|
||||
dynui = zalloc ( len );
|
||||
if ( ! dynui )
|
||||
return NULL;
|
||||
name_copy = ( ( void * ) ( dynui + 1 ) );
|
||||
title_copy = ( name_copy + name_len );
|
||||
|
||||
/* Initialise user interface */
|
||||
if ( name ) {
|
||||
strcpy ( name_copy, name );
|
||||
dynui->name = name_copy;
|
||||
}
|
||||
strcpy ( title_copy, title );
|
||||
dynui->title = title_copy;
|
||||
INIT_LIST_HEAD ( &dynui->items );
|
||||
|
||||
/* Add to list of user interfaces */
|
||||
list_add_tail ( &dynui->list, &dynamic_uis );
|
||||
|
||||
DBGC ( dynui, "DYNUI %s created with title \"%s\"\n",
|
||||
dynui->name, dynui->title );
|
||||
|
||||
return dynui;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dynamic user interface item
|
||||
*
|
||||
* @v dynui Dynamic user interface
|
||||
* @v name Name, or NULL
|
||||
* @v text Text, or NULL
|
||||
* @v shortcut Shortcut key
|
||||
* @v is_default Item is the default item
|
||||
* @ret item User interface item, or NULL on failure
|
||||
*/
|
||||
struct dynamic_item * add_dynui_item ( struct dynamic_ui *dynui,
|
||||
const char *name, const char *text,
|
||||
int shortcut, int is_default ) {
|
||||
struct dynamic_item *item;
|
||||
size_t name_len;
|
||||
size_t text_len;
|
||||
size_t len;
|
||||
char *name_copy;
|
||||
char *text_copy;
|
||||
|
||||
/* Use empty text if none given */
|
||||
if ( ! text )
|
||||
text = "";
|
||||
|
||||
/* Allocate item */
|
||||
name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
|
||||
text_len = ( strlen ( text ) + 1 /* NUL */ );
|
||||
len = ( sizeof ( *item ) + name_len + text_len );
|
||||
item = zalloc ( len );
|
||||
if ( ! item )
|
||||
return NULL;
|
||||
name_copy = ( ( void * ) ( item + 1 ) );
|
||||
text_copy = ( name_copy + name_len );
|
||||
|
||||
/* Initialise item */
|
||||
if ( name ) {
|
||||
strcpy ( name_copy, name );
|
||||
item->name = name_copy;
|
||||
}
|
||||
strcpy ( text_copy, text );
|
||||
item->text = text_copy;
|
||||
item->shortcut = shortcut;
|
||||
item->is_default = is_default;
|
||||
|
||||
/* Add to list of items */
|
||||
list_add_tail ( &item->list, &dynui->items );
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy dynamic user interface
|
||||
*
|
||||
* @v dynui Dynamic user interface
|
||||
*/
|
||||
void destroy_dynui ( struct dynamic_ui *dynui ) {
|
||||
struct dynamic_item *item;
|
||||
struct dynamic_item *tmp;
|
||||
|
||||
/* Remove from list of user interfaces */
|
||||
list_del ( &dynui->list );
|
||||
|
||||
/* Free items */
|
||||
list_for_each_entry_safe ( item, tmp, &dynui->items, list ) {
|
||||
list_del ( &item->list );
|
||||
free ( item );
|
||||
}
|
||||
|
||||
/* Free user interface */
|
||||
free ( dynui );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find dynamic user interface
|
||||
*
|
||||
* @v name User interface name, or NULL
|
||||
* @ret dynui Dynamic user interface, or NULL if not found
|
||||
*/
|
||||
struct dynamic_ui * find_dynui ( const char *name ) {
|
||||
struct dynamic_ui *dynui;
|
||||
|
||||
list_for_each_entry ( dynui, &dynamic_uis, list ) {
|
||||
if ( ( dynui->name == name ) ||
|
||||
( strcmp ( dynui->name, name ) == 0 ) ) {
|
||||
return dynui;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user