aboutsummaryrefslogtreecommitdiffstats
path: root/src/hci/tui
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2024-05-15 14:10:33 +0100
committerMichael Brown <mcb30@ipxe.org>2024-05-15 14:22:01 +0100
commitdc118c53696af6a0b1a8ee78fc9a4d28a217fb21 (patch)
treea651a3f7fdf3889bd21f74c9fcd2aa8ad71431c6 /src/hci/tui
parentd7e58c5a812988c341ec4ad19f79faf067388d58 (diff)
downloadipxe-dc118c53696af6a0b1a8ee78fc9a4d28a217fb21.tar.gz
[hci] Provide a general concept of a text widget set
Create a generic abstraction of a text widget, refactor the existing editable text box widget to use this abstraction, add an implementation of a non-editable text label widget, and generalise the login user interface to use this generic widget abstraction. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/hci/tui')
-rw-r--r--src/hci/tui/login_ui.c106
-rw-r--r--src/hci/tui/settings_ui.c14
-rw-r--r--src/hci/tui/widget_ui.c143
3 files changed, 187 insertions, 76 deletions
diff --git a/src/hci/tui/login_ui.c b/src/hci/tui/login_ui.c
index bd24991cd..b76afb92e 100644
--- a/src/hci/tui/login_ui.c
+++ b/src/hci/tui/login_ui.c
@@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <curses.h>
#include <ipxe/console.h>
#include <ipxe/settings.h>
+#include <ipxe/label.h>
#include <ipxe/editbox.h>
#include <ipxe/keys.h>
#include <ipxe/ansicol.h>
@@ -45,90 +46,55 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define USERNAME_ROW ( ( LINES / 2U ) - 2U )
#define PASSWORD_LABEL_ROW ( ( LINES / 2U ) + 2U )
#define PASSWORD_ROW ( ( LINES / 2U ) + 4U )
-#define LABEL_COL ( ( COLS / 2U ) - 4U )
-#define EDITBOX_COL ( ( COLS / 2U ) - 10U )
-#define EDITBOX_WIDTH 20U
+#define WIDGET_COL ( ( COLS / 2U ) - 10U )
+#define WIDGET_WIDTH 20U
int login_ui ( void ) {
char *username;
char *password;
- struct edit_box username_box;
- struct edit_box password_box;
- struct edit_box *current_box = &username_box;
- int key;
- int rc = -EINPROGRESS;
+ struct {
+ struct widgets widgets;
+ struct label username_label;
+ struct label password_label;
+ struct edit_box username_box;
+ struct edit_box password_box;
+ } widgets;
+ int rc;
/* Fetch current setting values */
fetchf_setting_copy ( NULL, &username_setting, NULL, NULL, &username );
fetchf_setting_copy ( NULL, &password_setting, NULL, NULL, &password );
- /* Initialise UI */
- initscr();
- start_color();
- init_editbox ( &username_box, &username, NULL, USERNAME_ROW,
- EDITBOX_COL, EDITBOX_WIDTH, 0 );
- init_editbox ( &password_box, &password, NULL, PASSWORD_ROW,
- EDITBOX_COL, EDITBOX_WIDTH, EDITBOX_STARS );
+ /* Construct user interface */
+ memset ( &widgets, 0, sizeof ( widgets ) );
+ init_widgets ( &widgets.widgets, NULL );
+ init_label ( &widgets.username_label, USERNAME_LABEL_ROW, WIDGET_COL,
+ WIDGET_WIDTH, "Username" );
+ init_label ( &widgets.password_label, PASSWORD_LABEL_ROW, WIDGET_COL,
+ WIDGET_WIDTH, "Password" );
+ init_editbox ( &widgets.username_box, USERNAME_ROW, WIDGET_COL,
+ WIDGET_WIDTH, 0, &username );
+ init_editbox ( &widgets.password_box, PASSWORD_ROW, WIDGET_COL,
+ WIDGET_WIDTH, WIDGET_SECRET, &password );
+ add_widget ( &widgets.widgets, &widgets.username_label.widget );
+ add_widget ( &widgets.widgets, &widgets.password_label.widget );
+ add_widget ( &widgets.widgets, &widgets.username_box.widget );
+ add_widget ( &widgets.widgets, &widgets.password_box.widget );
- /* Draw initial UI */
- color_set ( CPAIR_NORMAL, NULL );
- erase();
- attron ( A_BOLD );
- mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" );
- mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" );
- attroff ( A_BOLD );
- color_set ( CPAIR_EDIT, NULL );
- draw_editbox ( &username_box );
- draw_editbox ( &password_box );
-
- /* Main loop */
- while ( rc == -EINPROGRESS ) {
-
- draw_editbox ( current_box );
-
- key = getkey ( 0 );
- switch ( key ) {
- case KEY_DOWN:
- current_box = &password_box;
- break;
- case KEY_UP:
- current_box = &username_box;
- break;
- case TAB:
- current_box = ( ( current_box == &username_box ) ?
- &password_box : &username_box );
- break;
- case KEY_ENTER:
- if ( current_box == &username_box ) {
- current_box = &password_box;
- } else {
- rc = 0;
- }
- break;
- case CTRL_C:
- case ESC:
- rc = -ECANCELED;
- break;
- default:
- edit_editbox ( current_box, key );
- break;
- }
- }
-
- /* Terminate UI */
- color_set ( CPAIR_NORMAL, NULL );
- erase();
- endwin();
+ /* Present user interface */
+ if ( ( rc = widget_ui ( &widgets.widgets ) ) != 0 )
+ goto err_ui;
/* Store settings on successful completion */
- if ( rc == 0 )
- rc = storef_setting ( NULL, &username_setting, username );
- if ( rc == 0 )
- rc = storef_setting ( NULL, &password_setting, password );
+ if ( ( rc = storef_setting ( NULL, &username_setting, username ) ) !=0)
+ goto err_store_username;
+ if ( ( rc = storef_setting ( NULL, &password_setting, password ) ) !=0)
+ goto err_store_password;
- /* Free setting values */
+ err_store_username:
+ err_store_password:
+ err_ui:
free ( username );
free ( password );
-
return rc;
}
diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c
index 95cbd7758..53bf24d1a 100644
--- a/src/hci/tui/settings_ui.c
+++ b/src/hci/tui/settings_ui.c
@@ -108,6 +108,8 @@ struct settings_ui {
struct jump_scroller scroll;
/** Current row */
struct settings_ui_row row;
+ /** Widget set used for editing setting */
+ struct widgets widgets;
};
/**
@@ -164,10 +166,11 @@ static unsigned int select_setting_row ( struct settings_ui *ui,
}
/* Initialise edit box */
- init_editbox ( &ui->row.editbox, &ui->row.buf, NULL, ui->row.row,
+ memset ( &ui->row.editbox, 0, sizeof ( ui->row.editbox ) );
+ init_editbox ( &ui->row.editbox, ui->row.row,
( SETTINGS_LIST_COL +
offsetof ( typeof ( *text ), u.setting.value ) ),
- sizeof ( text->u.setting.value ), 0 );
+ sizeof ( text->u.setting.value ), 0, &ui->row.buf );
return count;
}
@@ -250,7 +253,7 @@ static void draw_setting_row ( struct settings_ui *ui ) {
static int edit_setting ( struct settings_ui *ui, int key ) {
assert ( ui->row.setting.name != NULL );
ui->row.editing = 1;
- return edit_editbox ( &ui->row.editbox, key );
+ return edit_widget ( &ui->widgets, &ui->row.editbox.widget, key );
}
/**
@@ -454,6 +457,7 @@ static int main_loop ( struct settings *settings ) {
/* Print initial screen content */
color_set ( CPAIR_NORMAL, NULL );
memset ( &ui, 0, sizeof ( ui ) );
+ init_widgets ( &ui.widgets, NULL );
select_settings ( &ui, settings );
while ( 1 ) {
@@ -477,9 +481,7 @@ static int main_loop ( struct settings *settings ) {
assert ( ui.row.setting.name != NULL );
/* Redraw edit box */
- color_set ( CPAIR_EDIT, NULL );
- draw_editbox ( &ui.row.editbox );
- color_set ( CPAIR_NORMAL, NULL );
+ draw_widget ( &ui.widgets, &ui.row.editbox.widget );
/* Process keypress */
key = edit_setting ( &ui, getkey ( 0 ) );
diff --git a/src/hci/tui/widget_ui.c b/src/hci/tui/widget_ui.c
new file mode 100644
index 000000000..5079eefdd
--- /dev/null
+++ b/src/hci/tui/widget_ui.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2024 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
+ *
+ * Text widget UI
+ *
+ */
+
+#include <errno.h>
+#include <curses.h>
+#include <ipxe/ansicol.h>
+#include <ipxe/widget.h>
+
+/**
+ * Find editable widget in widget set
+ *
+ * @v widgets Text widget set
+ * @v index Editable widget index
+ * @ret widget Editable widget, or NULL
+ */
+static struct widget * find_widget ( struct widgets *widgets,
+ unsigned int index ) {
+ struct widget *widget;
+
+ list_for_each_entry ( widget, &widgets->list, list ) {
+ if ( ! ( widget->flags & WIDGET_EDITABLE ) )
+ continue;
+ if ( index-- == 0 )
+ return widget;
+ }
+ return NULL;
+}
+
+/**
+ * Text widget user interface main loop
+ *
+ * @v widgets Text widget set
+ * @ret rc Return status code
+ */
+static int widget_ui_loop ( struct widgets *widgets ) {
+ struct widget *widget;
+ unsigned int current;
+ unsigned int count;
+ int key;
+
+ /* Draw all widgets */
+ list_for_each_entry ( widget, &widgets->list, list )
+ draw_widget ( widgets, widget );
+
+ /* Count editable widgets */
+ count = 0;
+ while ( find_widget ( widgets, count ) != NULL )
+ count++;
+
+ /* Main loop */
+ current = 0;
+ while ( 1 ) {
+
+ /* Identify current widget */
+ widget = find_widget ( widgets, current );
+ if ( ! widget )
+ return -ENOENT;
+
+ /* Redraw current widget */
+ draw_widget ( widgets, widget );
+
+ /* Process keypress */
+ key = edit_widget ( widgets, widget, getkey ( 0 ) );
+ switch ( key ) {
+ case KEY_UP:
+ if ( current > 0 )
+ current--;
+ break;
+ case KEY_DOWN:
+ if ( ++current == count )
+ current--;
+ break;
+ case TAB:
+ if ( ++current == count )
+ current = 0;
+ break;
+ case KEY_ENTER:
+ current++;
+ if ( current >= count )
+ return 0;
+ break;
+ case CTRL_C:
+ case ESC:
+ return -ECANCELED;
+ default:
+ /* Do nothing for unrecognised keys or edit errors */
+ break;
+ }
+ }
+}
+
+/**
+ * Present text widget user interface
+ *
+ * @v widgets Text widget set
+ * @ret rc Return status code
+ */
+int widget_ui ( struct widgets *widgets ) {
+ int rc;
+
+ /* Initialise UI */
+ initscr();
+ start_color();
+ color_set ( CPAIR_NORMAL, NULL );
+ erase();
+
+ /* Run main loop */
+ rc = widget_ui_loop ( widgets );
+
+ /* Terminate UI */
+ color_set ( CPAIR_NORMAL, NULL );
+ endwin();
+
+ return rc;
+}