Skip to content

Commit

Permalink
[hci] Provide a general concept of a text widget set
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
mcb30 committed May 15, 2024
1 parent d7e58c5 commit dc118c5
Show file tree
Hide file tree
Showing 9 changed files with 509 additions and 140 deletions.
65 changes: 32 additions & 33 deletions src/hci/mucurses/widgets/editbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <string.h>
#include <assert.h>
#include <ipxe/ansicol.h>
#include <ipxe/editbox.h>

/** @file
Expand All @@ -35,39 +36,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#define EDITBOX_MIN_CHARS 3

/**
* Initialise text box widget
*
* @v box Editable text box widget
* @v buf Dynamically allocated string buffer
* @v win Containing window
* @v row Row
* @v col Starting column
* @v width Width
* @v flags Flags
*/
void init_editbox ( struct edit_box *box, char **buf,
WINDOW *win, unsigned int row, unsigned int col,
unsigned int width, unsigned int flags ) {
memset ( box, 0, sizeof ( *box ) );
init_editstring ( &box->string, buf );
box->string.cursor = ( *buf ? strlen ( *buf ) : 0 );
box->win = ( win ? win : stdscr );
box->row = row;
box->col = col;
box->width = width;
box->flags = flags;
}

/**
* Draw text box widget
*
* @v box Editable text box widget
*
* @v widgets Text widget set
* @v widget Text widget
*/
void draw_editbox ( struct edit_box *box ) {
static void draw_editbox ( struct widgets *widgets, struct widget *widget ) {
struct edit_box *box = container_of ( widget, struct edit_box, widget );
const char *content = *(box->string.buf);
size_t width = box->width;
size_t width = widget->width;
char buf[ width + 1 ];
signed int cursor_offset, underflow, overflow, first;
size_t len;
Expand All @@ -93,15 +71,36 @@ void draw_editbox ( struct edit_box *box ) {
len = ( content ? ( strlen ( content ) - first ) : 0 );
if ( len > width )
len = width;
if ( box->flags & EDITBOX_STARS ) {
if ( widget->flags & WIDGET_SECRET ) {
memset ( buf, '*', len );
} else {
memcpy ( buf, ( content + first ), len );
}

/* Print box content and move cursor */
if ( ! box->win )
box->win = stdscr;
mvwprintw ( box->win, box->row, box->col, "%s", buf );
wmove ( box->win, box->row, ( box->col + cursor_offset ) );
color_set ( CPAIR_EDIT, NULL );
mvwprintw ( widgets->win, widget->row, widget->col, "%s", buf );
wmove ( widgets->win, widget->row, ( widget->col + cursor_offset ) );
color_set ( CPAIR_NORMAL, NULL );
}

/**
* Edit text box widget
*
* @v widgets Text widget set
* @v widget Text widget
* @v key Key pressed by user
* @ret key Key returned to application, or zero
*/
static int edit_editbox ( struct widgets *widgets __unused,
struct widget *widget, int key ) {
struct edit_box *box = container_of ( widget, struct edit_box, widget );

return edit_string ( &box->string, key );
}

/** Text box widget operations */
struct widget_operations editbox_operations = {
.draw = draw_editbox,
.edit = edit_editbox,
};
77 changes: 77 additions & 0 deletions src/hci/mucurses/widgets/label.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2024 Michael Brown <[email protected]>.
*
* 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 );

#include <string.h>
#include <assert.h>
#include <ipxe/label.h>

/** @file
*
* Text label widget
*
*/

/**
* Draw text label widget
*
* @v widgets Text widget set
* @v widget Text widget
*/
static void draw_label ( struct widgets *widgets, struct widget *widget ) {
struct label *label = container_of ( widget, struct label, widget );
unsigned int width = widget->width;
unsigned int col = widget->col;
const char *text = label->text;

/* Centre label if width is non-zero */
if ( width )
col += ( ( width - strlen ( text ) ) / 2 );

/* Print label content */
attron ( A_BOLD );
mvwprintw ( widgets->win, widget->row, col, "%s", text );
attroff ( A_BOLD );
}

/**
* Edit text label widget
*
* @v widgets Text widget set
* @v widget Text widget
* @v key Key pressed by user
* @ret key Key returned to application, or zero
*/
static int edit_label ( struct widgets *widgets __unused,
struct widget *widget __unused, int key ) {

/* Cannot be edited */
return key;
}

/** Text label widget operations */
struct widget_operations label_operations = {
.draw = draw_label,
.edit = edit_label,
};
106 changes: 36 additions & 70 deletions src/hci/tui/login_ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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;
}
14 changes: 8 additions & 6 deletions src/hci/tui/settings_ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 );
}

/**
Expand Down Expand Up @@ -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 ) {
Expand All @@ -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 ) );
Expand Down
Loading

0 comments on commit dc118c5

Please sign in to comment.