From 37bc6c409e9f1da5ac596f4f508453a74fd215c2 Mon Sep 17 00:00:00 2001
From: b <rowerynaksiezycu@gmail.com>
Date: Wed, 1 Jan 2025 23:13:27 +0100
Subject: [PATCH] selected option is underlined, no separate states for
 options, use macros for buffer pointers

---
 aix.c         |  16 +-
 ctrl.c        |  37 ++--
 debug.c       |  17 +-
 gui.c         | 458 ++++++++++++++++++++++----------------------------
 gui.h         |  43 +++--
 klavirko-ui.h |  14 +-
 lcd.c         | 131 +++++++++++----
 lcd.h         |  22 ++-
 8 files changed, 371 insertions(+), 367 deletions(-)

diff --git a/aix.c b/aix.c
index c2e9542..821e285 100644
--- a/aix.c
+++ b/aix.c
@@ -1,6 +1,6 @@
 /* ANALOG INPUT EXPANDER */
 /*
-Copyright 2021 Balthasar Szczepański
+Copyright 2021, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -50,16 +50,13 @@ inline void int_aix_rx (void) // received byte from AIX
 	
 	data = AIX_RX__SDR; // get byte
 	
-	if((aix_buffer_w + 1 == aix_buffer_r) || (aix_buffer_w + 1 == aix_buffer_r + N_AIX_BUFFER)) // buffer overflow
+	if(FULL_BP(aix_buffer_w, aix_buffer_r, N_AIX_BUFFER)) // buffer overflow
 		{}
 	else
 	{
 		aix_buffer[aix_buffer_w] = data;
 		// advance the pointer
-		if (aix_buffer_w >= N_AIX_BUFFER - 1)
-			aix_buffer_w = 0;
-		else
-			++aix_buffer_w;
+		ADVANCE_BP(aix_buffer_w, N_AIX_BUFFER);
 	}
 }
 
@@ -120,14 +117,11 @@ void handle_aix (void)
 	uint8_t data;
 	int16_t diff;
 	
-	if (aix_buffer_r != aix_buffer_w) // data waiting in buffer
+	if (NOT_EMPTY_BP(aix_buffer_w, aix_buffer_r, N_AIX_BUFFER)) // data waiting in buffer
 	{
 		// get data; advance pointer
 		data = aix_buffer[aix_buffer_r];
-		if(aix_buffer_r >= N_AIX_BUFFER - 1)
-			aix_buffer_r = 0;
-		else
-			++aix_buffer_r;
+		ADVANCE_BP(aix_buffer_r, N_AIX_BUFFER);
 		
 		if (data == '\n') //end of frame
 		{
diff --git a/ctrl.c b/ctrl.c
index 9851912..8b795db 100644
--- a/ctrl.c
+++ b/ctrl.c
@@ -1,6 +1,6 @@
 /* COMMUNICATING WITH MAIN CONTROLLER */
 /*
-Copyright 2021, 2024 Balthasar Szczepański
+Copyright 2021, 2024, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -58,16 +58,12 @@ inline void int_ctrl_rx(void) // received byte from CTRL
 	
 	data = CTRL_RX__SDR; // get byte
 	
-	if((ctrl_rxbuffer_w + 1 == ctrl_rxbuffer_r) || (ctrl_rxbuffer_w + 1 == ctrl_rxbuffer_r + N_CTRL_RXBUFFER)) // buffer overflow
+	if (FULL_BP(ctrl_rxbuffer_w, ctrl_rxbuffer_r, N_CTRL_RXBUFFER)) // buffer overflow
 		ctrl_error |= ERR_OVERFLOW;
 	else
 	{
 		ctrl_rxbuffer[ctrl_rxbuffer_w] = data;
-		// advance the pointer
-		if (ctrl_rxbuffer_w >= N_CTRL_RXBUFFER - 1)
-			ctrl_rxbuffer_w = 0;
-		else
-			++ctrl_rxbuffer_w;
+		ADVANCE_BP(ctrl_rxbuffer_w, N_CTRL_RXBUFFER);
 	}
 }
 
@@ -243,7 +239,7 @@ void handle_ctrl (void)
 	
 	while (ctrl_state == CTRL_SEND) // send the command
 	{
-		if((ctrl_txbuffer_w + 1 == ctrl_txbuffer_r) || (ctrl_txbuffer_w + 1 == ctrl_txbuffer_r + N_CTRL_TXBUFFER)) // no place in buffer
+		if (FULL_BP(ctrl_txbuffer_w, ctrl_txbuffer_r, N_CTRL_TXBUFFER)) // no place in buffer
 			break;
 		
 		if (ctrl_index < 0) // start of frame, command id
@@ -257,7 +253,7 @@ void handle_ctrl (void)
 		{
 			io = '\n';
 			ctrl_state = CTRL_SWITCH; // GOTO next state
-			ctrl_rxbuffer_r = ctrl_rxbuffer_w;
+			CLEAR_BP(ctrl_rxbuffer_w, ctrl_rxbuffer_r, N_CTRL_RXBUFFER);
 		}
 		else // data byte
 		{
@@ -285,24 +281,16 @@ void handle_ctrl (void)
 		
 		// put to buffer, adnvance the pointer
 		ctrl_txbuffer[ctrl_txbuffer_w] = io;
-		if (ctrl_txbuffer_w >= N_CTRL_TXBUFFER - 1)
-			ctrl_txbuffer_w = 0;
-		else
-			++ctrl_txbuffer_w;
+		ADVANCE_BP(ctrl_txbuffer_w, N_CTRL_TXBUFFER);
 	}
 	
-	if (ctrl_txbuffer_r != ctrl_txbuffer_w) // data in output buffer
+	if (NOT_EMPTY_BP(ctrl_txbuffer_w, ctrl_txbuffer_r, N_CTRL_TXBUFFER)) // data in output buffer
 	{
 		if(!(CTRL_TX__SSR & 0b01000000)) // uart is ready
 		{
 			CTRL_TX__IF = 0;
 			CTRL_TX__SDR = ctrl_txbuffer[ctrl_txbuffer_r]; // send the byte
-			
-			// advance the pointer
-			if (ctrl_txbuffer_r >= N_CTRL_RXBUFFER - 1)
-				ctrl_txbuffer_r = 0;
-			else
-				++ctrl_txbuffer_r;
+			ADVANCE_BP(ctrl_txbuffer_r, N_CTRL_RXBUFFER); // advance the pointer
 		}
 	}
 	
@@ -333,20 +321,17 @@ void handle_ctrl (void)
 		ctrl_resp = CMD_NOP;
 	}
 	
-	while (ctrl_rxbuffer_r != ctrl_rxbuffer_w) // data in input buffer
+	while (NOT_EMPTY_BP(ctrl_rxbuffer_w, ctrl_rxbuffer_r, N_CTRL_RXBUFFER)) // data in input buffer
 	{
 		// get the byte, advance the pointer
 		io = ctrl_rxbuffer[ctrl_rxbuffer_r];
-		if(ctrl_rxbuffer_r >= N_CTRL_RXBUFFER -1 )
-			ctrl_rxbuffer_r = 0;
-		else
-			++ctrl_rxbuffer_r;
+		ADVANCE_BP(ctrl_rxbuffer_r, N_CTRL_RXBUFFER);
 		
 		if (io == CMD_ERR) // received a complain from CTRL
 		{
 			// drop any action, immediately switch to listen
 			ctrl_state = CTRL_RECEIVE;
-			ctrl_txbuffer_r = ctrl_txbuffer_w;
+			CLEAR_BP(ctrl_txbuffer_w, ctrl_txbuffer_r, N_CTRL_TXBUFFER);
 		}
 		
 		if (ctrl_state == CTRL_RECEIVE) // actually expecting to receive
diff --git a/debug.c b/debug.c
index 598271c..142c0c4 100644
--- a/debug.c
+++ b/debug.c
@@ -1,6 +1,6 @@
 /* DEBUG SERIAL OUTPUT */
 /*
-Copyright 2021 Balthasar Szczepański
+Copyright 2021, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -24,7 +24,7 @@ void handle_debug(void)
 {
 	uint8_t byte;
 	
-	if(debug_buffer_r != debug_buffer_w) // data waiting in buffer
+	if (NOT_EMPTY_BP(debug_buffer_w, debug_buffer_r, N_DEBUG_BUFFER)) // data waiting in buffer
 	{
 		byte = debug_buffer[debug_buffer_r]; // get the byte
 		
@@ -35,11 +35,7 @@ void handle_debug(void)
 		}
 		else
 			return;
-		// advance the pointer
-		if(debug_buffer_r >= N_DEBUG_BUFFER - 1)
-			debug_buffer_r = 0;
-		else
-			++debug_buffer_r;
+		ADVANCE_BP(debug_buffer_r, N_DEBUG_BUFFER); // advance the pointer
 	}
 }
 
@@ -48,7 +44,7 @@ void debug_byte ( // send a byte to debug output
 	const uint8_t blocking
 )
 {
-	while((debug_buffer_w + 1 == debug_buffer_r) || (debug_buffer_w + 1 == debug_buffer_r + N_DEBUG_BUFFER))
+	while (FULL_BP(debug_buffer_w, debug_buffer_r, N_DEBUG_BUFFER))
 	{
 		if (blocking)
 			handle_debug();
@@ -56,10 +52,7 @@ void debug_byte ( // send a byte to debug output
 			return;
 	}
 	debug_buffer[debug_buffer_w] = value;
-	if(debug_buffer_w >= N_DEBUG_BUFFER - 1)
-		debug_buffer_w = 0;
-	else
-		++debug_buffer_w;
+	ADVANCE_BP(debug_buffer_w, N_DEBUG_BUFFER);
 }
 
 void debug_string ( // send a string to debug output
diff --git a/gui.c b/gui.c
index a863a5c..5106084 100644
--- a/gui.c
+++ b/gui.c
@@ -1,6 +1,6 @@
 /* GUI */
 /*
-Copyright 2021, 2022, 2024 Balthasar Szczepański
+Copyright 2021, 2022, 2024, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -49,6 +49,9 @@ volatile uint8_t  gui_event_w = 0;
          uint8_t  gui_return_state = GUI_WAVE;
          uint8_t  gui_errors = 0;
          uint8_t  gui_accepted_errors = GUI_ERRF_ALL;
+         int8_t   gui_choice = GUI_NOCHOICE;
+         int16_t  gui_used_voice_page = -1;
+         int16_t  gui_used_voice_id = -1;
 
          uint8_t  gui_page=0;
          uint8_t  gui_name[N_NAME+1] = {[0 ... (N_NAME)] = '\0'};
@@ -73,16 +76,13 @@ const    uint8_t  gui_list_123[N_123+1] = LIST_123;
 
 inline void add_gui_event(const uint16_t event)
 {
-	if((gui_event_w + 1 == gui_event_r) || (gui_event_w + 1 == gui_event_r + N_GUI_EVENT)) // event buffer is full
+	if (FULL_BP(gui_event_w, gui_event_r, N_GUI_EVENT)) // event buffer is full
 		return;
 	else
 	{
 		// add event, advance pointer
 		gui_event[gui_event_w] = event;
-		if (gui_event_w >= N_GUI_EVENT - 1)
-			gui_event_w = 0;
-		else
-			++gui_event_w;
+		ADVANCE_BP(gui_event_w, N_GUI_EVENT);
 	}
 }
 
@@ -90,7 +90,7 @@ inline void reject_gui_events (void)
 {
 	button_valid = 0; // reject any already pressed buttons
 	button_hold_count = 0; // to not get a long hold in new state
-	gui_event_r = gui_event_w;
+	CLEAR_BP(gui_event_w, gui_event_r, N_GUI_EVENT);
 }
 
 inline void gui_trigger_error (const uint8_t error)
@@ -462,10 +462,14 @@ inline void gui_event_wave (const uint16_t event)
 		else if (event & (BUTTON_A | BUTTON_B))
 		{
 			gui_switch_wave();
+			gui_used_voice_page = -1;
+			gui_used_voice_id = -1;
 		}
 		else if (event & (BUTTON_C | BUTTON_D | BUTTON_E ))
 		{
 			gui_switch_adsr();
+			gui_used_voice_page = -1;
+			gui_used_voice_id = -1;
 		}
 		else if (event & BUTTON_F)
 		{
@@ -479,6 +483,8 @@ inline void gui_event_wave (const uint16_t event)
 				gui_lock_wave();
 				gui_lock_adsr();
 			}
+			gui_used_voice_page = -1;
+			gui_used_voice_id = -1;
 		}
 		break;
 	}
@@ -503,6 +509,7 @@ inline void gui_exec_wave (void) // redraw if needed
 inline void gui_gotostate_select (void)
 {
 	gui_state = GUI_SELECT;
+	// gui_choice = GUI_NOCHOICE;
 	draw_select();
 	reject_gui_events();
 }
@@ -535,11 +542,11 @@ inline void gui_event_select (const uint16_t event)
 				if (event & EVENT_LONG)
 				{
 					fs_delete_voice(id);
-					lcd_update_button(id, "");
+					lcd_update_button(id, "", gui_choice == id);
 					reject_gui_events();
 				}
 				else
-					lcd_update_button(id, GUI_BUTTONTEXT_CONFIRM_REMOVE);
+					lcd_update_button(id, GUI_BUTTONTEXT_CONFIRM_REMOVE, gui_choice == id);
 			}
 		}
 		else if (event & BUTTON_Y) // no need to check long hold
@@ -551,7 +558,7 @@ inline void gui_event_select (const uint16_t event)
 			if (fs_is_voice_stored(id))
 			{
 				if (event & EVENT_WAS_HOLD)
-					lcd_update_button(id, fs_page_names[id]);
+					lcd_update_button(id, fs_page_names[id], gui_choice == id);
 				else
 				{
 					gui_lock_adsr();
@@ -569,11 +576,22 @@ inline void gui_event_select (const uint16_t event)
 						ctrl_update_adsr();
 						gui_update_adsr();
 						gui_update_wave();
+						if (gui_choice != id)
+							lcd_select_button(gui_choice, 0);
+						lcd_select_button(id, 1);
+						gui_used_voice_page = fs_page;
+						gui_used_voice_id = id;
+						gui_choice = id;
 					}
 					else
 					{
 						gui_unlock_adsr();
 						gui_unlock_wave();
+						gui_used_voice_page = -1;
+						gui_used_voice_id = -1;
+						if ((gui_choice >= 0) && (gui_choice <= 5))
+							lcd_select_button(gui_choice, 0);
+						gui_choice = GUI_NOCHOICE;
 					}
 				}
 			}
@@ -581,6 +599,11 @@ inline void gui_event_select (const uint16_t event)
 			{
 				gui_unlock_adsr();
 				gui_unlock_wave();
+				gui_used_voice_page = -1;
+				gui_used_voice_id = -1;
+				if ((gui_choice >= 0) && (gui_choice <= 5))
+					lcd_select_button(gui_choice, 0);
+				gui_choice = GUI_NOCHOICE;
 			}
 		}
 		else if (event & BUTTON_X)
@@ -615,6 +638,7 @@ inline void gui_gotostate_name (const uint8_t new)
 		gui_name_pos = 0;
 	}
 	gui_state = GUI_NAME;
+	gui_choice = 2;
 	
 	gui_name_list = gui_list_ABC;
 	gui_name_maxcursor = N_ABC-1;
@@ -636,7 +660,8 @@ inline void gui_gotostate_name (const uint8_t new)
 		GUI_BUTTONTEXT_ABC,
 		GUI_BUTTONTEXT_abc,
 		GUI_BUTTONTEXT_123,
-		GUI_BUTTONTEXT_OK
+		GUI_BUTTONTEXT_OK,
+		gui_choice
 	);
 	reject_gui_events();
 	gui_ignore_event = new;
@@ -688,7 +713,7 @@ inline void gui_event_name (const uint16_t event)
 			}
 			else
 				gui_name[gui_name_pos] = '\0';
-			lcd_update_button(-1,gui_name);
+			lcd_update_button(-1, gui_name, 0);
 		}
 		else if (event & ( BUTTON_C | BUTTON_D | BUTTON_E ))
 		{
@@ -696,16 +721,28 @@ inline void gui_event_name (const uint16_t event)
 			{
 				gui_name_list = gui_list_ABC;
 				gui_name_maxcursor = N_ABC-1;
+				if (gui_choice != 2)
+					lcd_select_button(gui_choice, 0);
+				gui_choice = 2;
+				lcd_select_button(2, 1);
 			}
 			else if (event & BUTTON_D)
 			{
 				gui_name_list = gui_list_abc;
 				gui_name_maxcursor = N_abc-1;
+				if (gui_choice != 3)
+					lcd_select_button(gui_choice, 0);
+				gui_choice = 3;
+				lcd_select_button(3, 1);
 			}
 			else if (event & BUTTON_E)
 			{
 				gui_name_list = gui_list_123;
 				gui_name_maxcursor = N_123-1;
+				if (gui_choice != 4)
+					lcd_select_button(gui_choice, 0);
+				gui_choice = 4;
+				lcd_select_button(4, 1);
 			}
 			lcd_draw_name_list(gui_name_list);
 			if (gui_name_cursor > gui_name_maxcursor)
@@ -754,7 +791,7 @@ inline void gui_exec_name (void) // do cursor blinking
 	if ((gui_name_pos < N_NAME) && (gui_name[gui_name_pos] != cursor))
 	{
 		gui_name[gui_name_pos] = cursor;
-		lcd_update_button(-1, gui_name);
+		lcd_update_button(-1, gui_name, 0);
 	}
 }
 
@@ -764,6 +801,7 @@ inline void gui_gotostate_select_save (void)
 {
 	// gui_return_state = gui_state;
 	gui_state = GUI_SELECT_SAVE;
+	// gui_choice = GUI_NOCHOICE;
 	draw_select_save();
 	reject_gui_events();
 }
@@ -792,7 +830,7 @@ inline void gui_event_select_save (const uint16_t event)
 		if (event & (BUTTON_ABCDEF))
 		{
 			if (fs_is_voice_stored(id))
-				lcd_update_button(id, GUI_BUTTONTEXT_CONFIRM_REPLACE);
+				lcd_update_button(id, GUI_BUTTONTEXT_CONFIRM_REPLACE, gui_choice==id);
 		}
 		break;
 	case EVENT_HOLD:
@@ -821,7 +859,7 @@ inline void gui_event_select_save (const uint16_t event)
 		if (event & (BUTTON_ABCDEF))
 		{
 			if (fs_is_voice_stored(id))
-				lcd_update_button(id, fs_page_names[id]);
+				lcd_update_button(id, fs_page_names[id], gui_choice==id);
 			else
 			{
 				fs_store_voice(
@@ -863,6 +901,12 @@ inline void gui_event_select_save (const uint16_t event)
 }
 
 // OPTIONS: menu with some settings
+//   TUNING:      change tuning of instrument
+//   TRANSPOSE:   shift by -12 to 12 semitones
+//   MIDI ID IN:  choose MIDI channel ID for input
+//   MIDI ID OUT: choose MIDI channel ID for output
+//   MIDI PEDAL:  allow / block MIDI pedal input
+//   TOTAL RESET  remove all stored voices from flash memory
 
 inline void gui_gotostate_options (void)
 {
@@ -872,6 +916,7 @@ inline void gui_gotostate_options (void)
 	make_text_midi_out ();
 	
 	gui_state = GUI_OPTIONS;
+	gui_choice = GUI_NOCHOICE;
 	lcd_draw_menu (6,
 		GUI_TITLE_OPTIONS,"",
 		text_tuning,
@@ -879,7 +924,8 @@ inline void gui_gotostate_options (void)
 		text_midi_in,
 		text_midi_out,
 		midi_pedal_en ? GUI_BUTTONTEXT_MIDI_PEDAL : GUI_BUTTONTEXT_MIDI_NOPEDAL,
-		GUI_BUTTONTEXT_RESET
+		GUI_BUTTONTEXT_RESET,
+		gui_choice
 	);
 	reject_gui_events();
 }
@@ -889,22 +935,68 @@ inline void gui_event_options (const uint16_t event)
 	switch (event & EVENT_BITS)
 	{
 	case EVENT_PRESS:
-		if (event & BUTTON_F)
-			lcd_update_button(5, GUI_BUTTONTEXT_CONFIRM_RESET);
+		if (event & BUTTON_A)
+		{
+			if (gui_choice != 0)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 0;
+			lcd_select_button(0, 1);
+			lcd_update_title(GUI_TITLE_OPTION_TUNING);
+		}
+		else if (event & BUTTON_B)
+		{
+			if (gui_choice != 1)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 1;
+			lcd_select_button(1, 1);
+			lcd_update_title(GUI_TITLE_OPTION_TRANSPOSE);
+		}
+		else if (event & BUTTON_C)
+		{
+			if (gui_choice != 2)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 2;
+			lcd_select_button(2, 1);
+			lcd_update_title(GUI_TITLE_OPTION_MIDI_ID);
+		}
+		else if (event & BUTTON_D)
+		{
+			if (gui_choice != 3)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 3;
+			lcd_select_button(3, 1);
+			lcd_update_title(GUI_TITLE_OPTION_MIDI_OUT_ID);
+		}
+		else if (event & BUTTON_E)
+		{
+			if (gui_choice != 4)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 4;
+			lcd_select_button(4, 1);
+			lcd_update_title(GUI_TITLE_OPTION_MIDI_PEDAL);
+		}
+		else if (event & BUTTON_F)
+		{
+			if (gui_choice != 5)
+				lcd_select_button(gui_choice, 0);
+			gui_choice = 5;
+			lcd_update_button(5, GUI_BUTTONTEXT_CONFIRM_RESET, 1);
+			lcd_update_title(GUI_TITLE_OPTION_TRANSPOSE);
+		}
 		break;
 	case EVENT_HOLD:
 		if (event & BUTTON_A)
 		{
 			set_tuning(DEFAULT_TUNING);
 			make_text_tuning();
-			lcd_update_button(0, text_tuning);
+			lcd_update_button(0, text_tuning, 1);
 			reject_gui_events();
 		}
 		else if (event & BUTTON_B)
 		{
 			set_transp(0);
 			make_text_transpose();
-			lcd_update_button(1, text_transpose);
+			lcd_update_button(1, text_transpose, 1);
 			reject_gui_events();
 		}
 		else if (event & BUTTON_C)
@@ -912,7 +1004,7 @@ inline void gui_event_options (const uint16_t event)
 			midi_id = N_MIDI_ID;
 			ctrl_update_midi();
 			make_text_midi_in();
-			lcd_update_button(2, text_midi_in);
+			lcd_update_button(2, text_midi_in, 1);
 			reject_gui_events();
 		}
 		else if (event & BUTTON_D)
@@ -920,7 +1012,7 @@ inline void gui_event_options (const uint16_t event)
 			midi_id_out = 0;
 			ctrl_update_midi();
 			make_text_midi_out();
-			lcd_update_button(3, text_midi_out);
+			lcd_update_button(3, text_midi_out, 1);
 			reject_gui_events();
 		}
 		// no long press on button E
@@ -935,237 +1027,92 @@ inline void gui_event_options (const uint16_t event)
 			gui_gotostate_wave();
 		else if (event & BUTTON_Y)
 			gui_gotostate_select();
-		else if (event & BUTTON_A)
-			gui_gotostate_tuning();
-		else if (event & BUTTON_B)
-			gui_gotostate_transpose();
-		else if (event & BUTTON_C)
-			gui_gotostate_midi_id();
-		else if (event & BUTTON_D)
-			gui_gotostate_midi_id_out();
 		else if (event & BUTTON_E)
 		{
 			if (midi_pedal_en)
 			{
 				midi_pedal_en = 0;
-				lcd_update_button(4, GUI_BUTTONTEXT_MIDI_NOPEDAL);
+				lcd_update_button(4, GUI_BUTTONTEXT_MIDI_NOPEDAL, 1);
 			}
 			else
 			{
 				midi_pedal_en = 1;
-				lcd_update_button(4, GUI_BUTTONTEXT_MIDI_PEDAL);
+				lcd_update_button(4, GUI_BUTTONTEXT_MIDI_PEDAL, 1);
 			}
 			ctrl_update_midi();
 		}
 		else if (event & BUTTON_F)
-				lcd_update_button(5, GUI_BUTTONTEXT_RESET);
-		break;
-	}
-}
-
-// TUNING: change tuning of instrument
-
-inline void gui_gotostate_tuning (void)
-{
-	make_text_tuning();
-	
-	gui_state = GUI_TUNING;
-	lcd_draw_menu (6,
-		GUI_TITLE_TUNING,"",
-		text_tuning, "", "", "", "", ""
-	);
-	reject_gui_events();
-}
-
-inline void gui_event_tuning (const uint16_t event)
-{
-	switch (event & EVENT_BITS)
-	{
-	case EVENT_HOLD:
-		if (event & BUTTON_A)
-		{
-			set_tuning(DEFAULT_TUNING);
-			make_text_tuning();
-			lcd_update_button(0, text_tuning);
-			reject_gui_events();
-		}
-		break;
-	case EVENT_RELEASE:
-		if (event & (BUTTON_A | BUTTON_X | BUTTON_Y))
-			gui_gotostate_options();
+			lcd_update_button(5, GUI_BUTTONTEXT_RESET, 1);
 		break;
 	case EVENT_JOG:
-		if ((event & JOG_BITS) == JOG_PLUS)
+		switch (gui_choice)
 		{
-			set_tuning(tuning + gui_jog_boost(event & JOG_TIME_BITS));
-		}
-		else
-		{
-			set_tuning(tuning - gui_jog_boost(event & JOG_TIME_BITS));
-		}
-		
-		make_text_tuning();
-		lcd_update_button(0, text_tuning);
-		break;
-	}
-}
-
-// TRANSPOSE: shift by -12 to 12 semitones
-
-inline void gui_gotostate_transpose (void)
-{
-	make_text_transpose();
-	
-	gui_state = GUI_TRANSPOSE;
-	lcd_draw_menu (6,
-		GUI_TITLE_TRANSPOSE,"",
-		"",text_transpose, "", "", "", ""
-	);
-	reject_gui_events();
-}
-
-inline void gui_event_transpose (const uint16_t event)
-{
-	switch (event & EVENT_BITS)
-	{
-	case EVENT_HOLD:
-		if (event & BUTTON_B)
-		{
-			set_transp(0);
+		case 0:
+			if ((event & JOG_BITS) == JOG_PLUS)
+			{
+				set_tuning(tuning + gui_jog_boost(event & JOG_TIME_BITS));
+			}
+			else
+			{
+				set_tuning(tuning - gui_jog_boost(event & JOG_TIME_BITS));
+			}
+			make_text_tuning();
+			lcd_update_button(0, text_tuning, 1);
+			break;
+		case 1:
+			if ((event & JOG_BITS) == JOG_PLUS)
+			{
+				if (transp<12)
+					set_transp(transp + 1);
+			}
+			else
+			{
+				if (transp>-12)
+					set_transp(transp - 1);
+			}
 			make_text_transpose();
-			lcd_update_button(1, text_transpose);
-			reject_gui_events();
-		}
-		break;
-	case EVENT_RELEASE:
-		if (event & (BUTTON_B | BUTTON_X | BUTTON_Y))
-			gui_gotostate_options();
-		break;
-	case EVENT_JOG:
-		if ((event & JOG_BITS) == JOG_PLUS)
-		{
-			if (transp<12)
-				set_transp(transp + 1);
-		}
-		else
-		{
-			if (transp>-12)
-				set_transp(transp - 1);
-		}
-		
-		make_text_transpose();
-		lcd_update_button(1, text_transpose);
-		break;
-	}
-}
-
-// MIDI_ID: choose MIDI channel ID for input
-
-inline void gui_gotostate_midi_id (void)
-{
-	make_text_midi_in();
-	
-	gui_state = GUI_MIDI_ID;
-	lcd_draw_menu (6,
-		GUI_TITLE_MIDI_ID,"",
-		"","",text_midi_in, "", "", ""
-	);
-	reject_gui_events();
-}
-
-inline void gui_event_midi_id (const uint16_t event)
-{
-	switch (event & EVENT_BITS)
-	{
-	case EVENT_HOLD:
-		if (event & BUTTON_C)
-		{
-			midi_id = N_MIDI_ID;
+			lcd_update_button(1, text_transpose, 1);
+			break;
+		case 2:
+			if ((event & JOG_BITS) == JOG_PLUS)
+			{
+				if (midi_id < N_MIDI_ID)
+					++midi_id;
+				else
+					midi_id = 0;
+			}
+			else
+			{
+				if (midi_id != 0)
+					--midi_id;
+				else
+					midi_id = N_MIDI_ID;
+			}
 			ctrl_update_midi();
 			make_text_midi_in();
-			lcd_update_button(2, text_midi_in);
-			reject_gui_events();
-		}
-		break;
-	case EVENT_RELEASE:
-		if (event & (BUTTON_C | BUTTON_X | BUTTON_Y))
-			gui_gotostate_options();
-		break;
-	case EVENT_JOG:
-		if ((event & JOG_BITS) == JOG_PLUS)
-		{
-			if (midi_id < N_MIDI_ID)
-				++midi_id;
-			else
-				midi_id = 0;
-		}
-		else
-		{
-			if (midi_id != 0)
-				--midi_id;
+			lcd_update_button(2, text_midi_in, 1);
+			break;
+		case 3:
+			if ((event & JOG_BITS) == JOG_PLUS)
+			{
+				if (midi_id_out < N_MIDI_ID-1)
+					++midi_id_out;
+				else
+					midi_id_out = 0;
+			}
 			else
-				midi_id = N_MIDI_ID;
-		}
-		
-		ctrl_update_midi();
-		make_text_midi_in();
-		lcd_update_button(2, text_midi_in);
-		break;
-	}
-}
-
-// MIDI_ID_OUT: choose MIDI channel ID for output
-
-inline void gui_gotostate_midi_id_out (void)
-{
-	make_text_midi_out();
-	
-	gui_state = GUI_MIDI_ID_OUT;
-	lcd_draw_menu (6,
-		GUI_TITLE_MIDI_ID_OUT,"",
-		"","","",text_midi_out, "", ""
-	);
-	reject_gui_events();
-}
-
-inline void gui_event_midi_id_out (const uint16_t event)
-{
-	switch (event & EVENT_BITS)
-	{
-	case EVENT_HOLD:
-		if (event & BUTTON_D)
-		{
-			midi_id_out = 0;
+			{
+				if (midi_id_out != 0)
+					--midi_id_out;
+				else
+					midi_id_out = N_MIDI_ID-1;
+			}
+			
 			ctrl_update_midi();
 			make_text_midi_out();
-			lcd_update_button(3, text_midi_out);
-			reject_gui_events();
-		}
-		break;
-	case EVENT_RELEASE:
-		if (event & (BUTTON_D | BUTTON_X | BUTTON_Y))
-			gui_gotostate_options();
-		break;
-	case EVENT_JOG:
-		if ((event & JOG_BITS) == JOG_PLUS)
-		{
-			if (midi_id_out < N_MIDI_ID-1)
-				++midi_id_out;
-			else
-				midi_id_out = 0;
-		}
-		else
-		{
-			if (midi_id_out != 0)
-				--midi_id_out;
-			else
-				midi_id_out = N_MIDI_ID-1;
+			lcd_update_button(3, text_midi_out, 1);
+			break;
 		}
-		
-		ctrl_update_midi();
-		make_text_midi_out();
-		lcd_update_button(3, text_midi_out);
-		break;
 	}
 }
 
@@ -1176,7 +1123,8 @@ inline void gui_gotostate_err_aix (void)
 	gui_state = GUI_ERR_AIX;
 	lcd_draw_menu(1,
 		GUI_TITLE_ERR_AIX,"",
-		"","","","","",GUI_BUTTONTEXT_IGNORE
+		"","","","","",GUI_BUTTONTEXT_IGNORE,
+		GUI_NOCHOICE
 	);
 	reject_gui_events();
 }
@@ -1200,7 +1148,8 @@ inline void gui_gotostate_err_ctrl (void)
 	gui_state = GUI_ERR_CTRL;
 	lcd_draw_menu(1,
 		GUI_TITLE_ERR_CTRL,"",
-		"","","","","",GUI_BUTTONTEXT_IGNORE
+		"","","","","",GUI_BUTTONTEXT_IGNORE,
+		GUI_NOCHOICE
 	);
 	reject_gui_events();
 }
@@ -1227,7 +1176,8 @@ inline void gui_gotostate_err_fs (void)
 		"","","",
 		GUI_BUTTONTEXT_FORMAT,
 		GUI_BUTTONTEXT_RECOVER,
-		GUI_BUTTONTEXT_IGNORE
+		GUI_BUTTONTEXT_IGNORE,
+		GUI_NOCHOICE
 	);
 	reject_gui_events();
 }
@@ -1259,7 +1209,8 @@ inline void gui_gotostate_total_reset (void)
 	gui_state = GUI_TOTAL_RESET;
 	lcd_draw_menu(0,
 		GUI_TITLE_RESET,"",
-		"","","","","",""
+		"","","","","","",
+		GUI_NOCHOICE
 	);
 	fs_format();
 	RESET_UI();
@@ -1270,14 +1221,11 @@ void handle_gui(void)
 {
 		uint16_t event;
 	
-	if (gui_event_r != gui_event_w) // event received
+	if (NOT_EMPTY_BP(gui_event_w, gui_event_r, N_GUI_EVENT)) // event received
 	{
 		// get event, advance pointer
 		event = gui_event[gui_event_r];
-		if(gui_event_r >= N_GUI_EVENT - 1)
-			gui_event_r = 0;
-		else
-			++gui_event_r;
+		ADVANCE_BP(gui_event_r, N_GUI_EVENT);
 		
 		// if ((event & EVENT_BITS) == EVENT_JOG)
 		// {
@@ -1337,18 +1285,6 @@ void handle_gui(void)
 		case GUI_OPTIONS:
 			gui_event_options(event);
 			break;
-		case GUI_TUNING:
-			gui_event_tuning(event);
-			break;
-		case GUI_TRANSPOSE:
-			gui_event_transpose(event);
-			break;
-		case GUI_MIDI_ID:
-			gui_event_midi_id(event);
-			break;
-		case GUI_MIDI_ID_OUT:
-			gui_event_midi_id_out(event);
-			break;
 		case GUI_ERR_AIX:
 			gui_event_err_aix(event);
 			break;
@@ -1375,10 +1311,6 @@ void handle_gui(void)
 	case GUI_SELECT:
 	case GUI_SELECT_SAVE:
 	case GUI_OPTIONS:
-	case GUI_TUNING:
-	case GUI_TRANSPOSE:
-	case GUI_MIDI_ID:
-	case GUI_MIDI_ID_OUT:
 	case GUI_ERR_AIX:
 	case GUI_ERR_CTRL:
 	case GUI_ERR_FS:
@@ -1496,6 +1428,11 @@ void draw_adsr (void) // envelope display
 void draw_select (void) // voice settings selection
 {
 	fs_load_page(gui_page);
+	if ((fs_page == gui_used_voice_page) && (gui_used_voice_id >= 0))
+		gui_choice = gui_used_voice_id;
+	else
+		gui_choice = GUI_NOCHOICE;
+	
 	make_text_select();
 	
 	lcd_draw_menu(6,
@@ -1506,13 +1443,19 @@ void draw_select (void) // voice settings selection
 		fs_page_names[2],
 		fs_page_names[3],
 		fs_page_names[4],
-		fs_page_names[5]
+		fs_page_names[5],
+		gui_choice
 	);
 }
 
 void draw_select_save (void) // voice setting save location selection
 {
 	fs_load_page(gui_page);
+	if ((fs_page == gui_used_voice_page) && (gui_used_voice_id >= 0))
+		gui_choice = gui_used_voice_id;
+	else
+		gui_choice = GUI_NOCHOICE;
+	
 	make_text_save();
 	
 	lcd_draw_menu(7,
@@ -1523,7 +1466,8 @@ void draw_select_save (void) // voice setting save location selection
 		fs_page_names[2],
 		fs_page_names[3],
 		fs_page_names[4],
-		fs_page_names[5]
+		fs_page_names[5],
+		gui_choice
 	);
 }
 
diff --git a/gui.h b/gui.h
index 62c4abc..78bfd27 100644
--- a/gui.h
+++ b/gui.h
@@ -1,6 +1,6 @@
 /* GUI */
 /*
-Copyright 2021, 2022, 2024 Balthasar Szczepański
+Copyright 2021, 2022, 2024, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -79,16 +79,16 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 #define EVENT_WAS_HOLD 0x1000
 #define EVENT_LONG     0x0800
 
+
+#define GUI_NOCHOICE (-128)
+
+
 #define GUI_INIT        0x00
 #define GUI_WAVE        0x01
 #define GUI_SELECT      0x02
 #define GUI_SELECT_SAVE 0x03
 #define GUI_NAME        0x04
 #define GUI_OPTIONS     0x10
-#define GUI_TUNING      0x11
-#define GUI_TRANSPOSE   0x12
-#define GUI_MIDI_ID     0x13
-#define GUI_MIDI_ID_OUT 0x14
 
 #define GUI_ERROR       0x80
 #define GUI_ERR_AIX     0x81
@@ -110,16 +110,21 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 #define N_abc 35
 #define N_123 42
 
-#define GUI_TITLE_NAME        "Save as:"
-#define GUI_TITLE_OPTIONS     "Options:"
-#define GUI_TITLE_TUNING      "Tuning:"
-#define GUI_TITLE_TRANSPOSE   "Transpose:"
-#define GUI_TITLE_MIDI_ID     "MIDI in ID:"
-#define GUI_TITLE_MIDI_ID_OUT "MIDI out ID:"
-#define GUI_TITLE_ERR_AIX     "AIX communication fail!"
-#define GUI_TITLE_ERR_CTRL    "CTRL communication fail!"
-#define GUI_TITLE_ERR_FS      "File system unformatted or damaged!"
-#define GUI_TITLE_RESET       "TERAS BENDZIE INNY $WIAT"
+#define GUI_TITLE_NAME     "Save as:"
+#define GUI_TITLE_TUNING   "Tuning:"
+#define GUI_TITLE_ERR_AIX  "AIX communication fail!"
+#define GUI_TITLE_ERR_CTRL "CTRL communication fail!"
+#define GUI_TITLE_ERR_FS   "File system unformatted or damaged!"
+#define GUI_TITLE_RESET    "TERAS BENDZIE INNY $WIAT"
+
+#define GUI_TITLE_OPTIONS            "Options:           "
+#define GUI_TITLE_OPTION_TUNING      "Options:          (tuning)"
+#define GUI_TITLE_OPTION_TRANSPOSE   "Options:          (transpose)"
+#define GUI_TITLE_OPTION_MIDI_ID     "Options:          (MIDI in ID)"
+#define GUI_TITLE_OPTION_MIDI_OUT_ID "Options:          (MIDI out ID)"
+#define GUI_TITLE_OPTION_MIDI_PEDAL  "Options:          (MIDI pedal)"
+#define GUI_TITLE_OPTION_RESET       "Options:          (TOTAL RESET)"
+
 
 #define GUI_BUTTONTEXT_DEL             "  <xx"
 #define GUI_BUTTONTEXT_SPACE           ""
@@ -203,10 +208,6 @@ inline void gui_gotostate_select (void);
 inline void gui_gotostate_name (const uint8_t new);
 inline void gui_gotostate_select_save (void);
 inline void gui_gotostate_options (void);
-inline void gui_gotostate_tuning (void);
-inline void gui_gotostate_transpose (void);
-inline void gui_gotostate_midi_id (void);
-inline void gui_gotostate_midi_id_out (void);
 inline void gui_gotostate_err_aix (void);
 inline void gui_gotostate_err_ctrl (void);
 inline void gui_gotostate_err_fs (void);
@@ -217,10 +218,6 @@ inline void gui_event_select (const uint16_t event);
 inline void gui_event_name (const uint16_t event);
 inline void gui_event_select_save (const uint16_t event);
 inline void gui_event_options (const uint16_t event);
-inline void gui_event_tuning (const uint16_t event);
-inline void gui_event_transp (const uint16_t event);
-inline void gui_event_midi_id (const uint16_t event);
-inline void gui_event_midi_id_out (const uint16_t event);
 inline void gui_event_err_aix (const uint16_t event);
 inline void gui_event_err_ctrl (const uint16_t event);
 inline void gui_event_err_fs (const uint16_t event);
diff --git a/klavirko-ui.h b/klavirko-ui.h
index 57016ec..774eb45 100644
--- a/klavirko-ui.h
+++ b/klavirko-ui.h
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 Balthasar Szczepański
+Copyright 2021, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -263,5 +263,17 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 	asm("br !!0xEF00;"); \
 }
 
+// common actions on buffer pointers
+// W  write pointer
+// R  read pointer
+// P  any pointer
+// N  buffer size
+#define ADVANCE_BP(P, N)      ((P<(N-1)) ? (++P) : (P=0))
+#define DIFF_BP(W, R, N)      ((W<R) ? (N + W - R) : W - R)
+#define FULL_BP(W, R, N)      (DIFF_BP(W, R, N) == (N-1))
+#define NOT_FULL_BP(W, R, N)  (DIFF_BP(W, R, N) != (N-1))
+#define EMPTY_BP(W, R, N)     (R == W)
+#define NOT_EMPTY_BP(W, R, N) (R != W)
+#define CLEAR_BP(W, R, N)     (R = W)
 
 #endif
diff --git a/lcd.c b/lcd.c
index 299fdc9..8a9f841 100644
--- a/lcd.c
+++ b/lcd.c
@@ -1,6 +1,6 @@
 /* LCD */
 /*
-Copyright 2021 Balthasar Szczepański
+Copyright 2021, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -69,8 +69,6 @@ inline void lcd_contrast (const uint16_t value)
 	lcd_write(LCD_MASTER, LCD_DATA, x >> LCD_Vop_HIGHSHIFT);
 }
 
-
-
 inline void setup_lcd (void)
 {
 	PER1 |= 0b00000001; //enable timer RJ
@@ -598,13 +596,17 @@ void lcd_draw_adsr (const uint8_t * const data)
 void lcd_subdraw_button (
 	uint16_t * const x,
 	const uint8_t type,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
 )
 {
 	uint16_t line1, line2, line3, line4, margin_l, margin_r;
 	uint16_t len, N;
 	uint16_t i, i0, i1, i2, i3, j0, j1, j2, j3;
 	uint8_t  chip = LCD_SLAVE;
+	uint8_t  underline;
+	
+	underline = selected ? 0x3C : 00;
 	
 	line1 = button_chars[type];
 	margin_l = button_lmargin[type];
@@ -652,7 +654,7 @@ void lcd_subdraw_button (
 			lcd_write(chip, LCD_DATA, font16[j0]);
 			++j0;
 			lcd_write(chip, LCD_DATA, 0x00);
-			lcd_write(chip, LCD_DATA, 0x00);
+			lcd_write(chip, LCD_DATA, underline);
 			++(*x);
 		}
 	}
@@ -680,7 +682,7 @@ void lcd_subdraw_button (
 			++j1;
 			lcd_write(chip, LCD_DATA, font16[j1]);
 			++j1;
-			lcd_write(chip, LCD_DATA, 0x00);
+			lcd_write(chip, LCD_DATA, underline);
 			++(*x);
 		}
 	}
@@ -709,7 +711,7 @@ void lcd_subdraw_button (
 			++j1;
 			lcd_write(chip, LCD_DATA, font8[j2]);
 			++j2;
-			lcd_write(chip, LCD_DATA, 0x00);
+			lcd_write(chip, LCD_DATA, underline);
 			++(*x);
 		}
 	}
@@ -741,7 +743,7 @@ void lcd_subdraw_button (
 			++j2;
 			lcd_write(chip, LCD_DATA, font8[j3]);
 			++j3;
-			lcd_write(chip, LCD_DATA, 0x00);
+			lcd_write(chip, LCD_DATA, underline);
 			++(*x);
 		}
 	}
@@ -753,7 +755,7 @@ void lcd_subdraw_button (
 		lcd_write(chip, LCD_DATA, 0x00);
 		lcd_write(chip, LCD_DATA, 0x00);
 		lcd_write(chip, LCD_DATA, 0x00);
-		lcd_write(chip, LCD_DATA, 0x00);
+		lcd_write(chip, LCD_DATA, 0x80);
 		++(*x);
 	}
 }
@@ -761,13 +763,17 @@ void lcd_subdraw_button (
 void lcd_subdraw_lowbutton8 (
 	uint16_t * const x,
 	const uint8_t type,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
 )
 {
 	uint16_t line1, margin_l, margin_r;
 	uint16_t len, N;
 	uint16_t i, i0, j0, j3;
 	uint8_t  chip = LCD_SLAVE;
+	uint8_t  underline;
+	
+	underline = selected ? 0x3C : 00;
 	
 	line1 = button_chars[type];
 	margin_l = button_lmargin[type];
@@ -802,7 +808,7 @@ void lcd_subdraw_lowbutton8 (
 		}
 		lcd_write(chip, LCD_DATA, font8[j0]);
 		++j0;
-		lcd_write(chip, LCD_DATA, 0x00);
+		lcd_write(chip, LCD_DATA, underline);
 		++(*x);
 	}
 
@@ -913,45 +919,57 @@ void lcd_draw_menu (
 	const uint8_t * const button_C,
 	const uint8_t * const button_D,
 	const uint8_t * const button_E,
- 	const uint8_t * const button_F
+	const uint8_t * const button_F,
+	const int8_t          selected
 ){
 	uint16_t x=0;
 	
 	lcd_setup_drawing(LCD_MONO, 0, 511, 0, 4);
 	
-	lcd_subdraw_button (&x, FULLTEXT - buttons, title);
+	lcd_subdraw_button (&x, FULLTEXT - buttons, title, 0);
 	switch (buttons)
 	{
 	case 7:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_0);
+		lcd_subdraw_button (&x, BUTTON_1X, button_0, selected == -1);
 	case 6:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_A);
+		lcd_subdraw_button (&x, BUTTON_1X, button_A, selected == 0);
 	case 5:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_B);
+		lcd_subdraw_button (&x, BUTTON_1X, button_B, selected == 1);
 	case 4:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_C);
+		lcd_subdraw_button (&x, BUTTON_1X, button_C, selected == 2);
 	case 3:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_D);
+		lcd_subdraw_button (&x, BUTTON_1X, button_D, selected == 3);
 	case 2:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_E);
+		lcd_subdraw_button (&x, BUTTON_1X, button_E, selected == 4);
 	case 1:
 		lcd_subdraw_divider(&x);
-		lcd_subdraw_button (&x, BUTTON_1X, button_F);
+		lcd_subdraw_button (&x, BUTTON_1X, button_F, selected == 5);
 	case 0:
 	default:
 		break;
 	}
 }
 
+void lcd_update_title (const uint8_t * const text)
+{
+	uint16_t x = 0;
+	
+	lcd_setup_drawing(LCD_MONO, 0, TITLE_6B_PIXELS-1, 0, 4);
+	
+	lcd_subdraw_button (&x, TITLE_6B, text, 0);
+}
+
+
 void lcd_update_button (
 	const int8_t id,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
 )
 {
 	uint16_t x;
@@ -960,7 +978,57 @@ void lcd_update_button (
 	
 	lcd_setup_drawing(LCD_MONO, x, x+BUTTON_1X_PIXELS-1, 0, 4);
 	
-	lcd_subdraw_button (&x, 0, text);
+	lcd_subdraw_button (&x, BUTTON_1X, text, selected);
+}
+
+void lcd_select_button (
+	const int8_t id,
+	const uint8_t selected
+)
+{
+	uint16_t x;
+	uint16_t N;
+	uint16_t margin_l, margin_r;
+	uint16_t i;
+	uint8_t  chip = LCD_SLAVE;
+	uint8_t  underline;
+	
+	if ((id < -1) || (id > 5))
+		return;
+	
+	x = TITLE_6B_PIXELS + 1 + id * (BUTTON_1X_PIXELS + 1);
+	
+	lcd_setup_drawing(LCD_MONO, x, x+BUTTON_1X_PIXELS-1, 4, 4);
+	
+	underline = selected ? 0x3C : 00;
+
+	margin_l = button_lmargin[BUTTON_1X];
+	margin_r = button_rmargin[BUTTON_1X];
+	N = button_chars[BUTTON_1X] <<3;
+	
+	for(i=0; i<margin_l; ++i) // left margin
+	{
+		if (x >= 256)
+			chip = LCD_MASTER;
+		lcd_write(chip, LCD_DATA, 0x00);
+		++x;
+	}
+	
+	for (i=0; i<N; ++i) // underline
+	{
+		if (x >= 256)
+			chip = LCD_MASTER;
+		lcd_write(chip, LCD_DATA, underline);
+		++x;
+	}
+	
+	for(i=0; i<margin_r; ++i) // right margin
+	{
+		if (x >= 256)
+			chip = LCD_MASTER;
+		lcd_write(chip, LCD_DATA, 0x00);
+		++x;
+	}
 }
 
 void lcd_draw_name_cursor (const uint8_t pos)
@@ -1014,31 +1082,32 @@ void lcd_draw_name_menu (
 	const uint8_t * const button_C,
 	const uint8_t * const button_D,
 	const uint8_t * const button_E,
-	const uint8_t * const button_F
+	const uint8_t * const button_F,
+	const int8_t          selected
 )
 {
 	uint16_t x = 0;
 	lcd_clear_screen(LCD_MONO);
 	lcd_setup_drawing(LCD_MONO, 0, TITLE_6B_PIXELS, 0, 4);
 	
-	lcd_subdraw_button (&x, TITLE_7B, title);
+	lcd_subdraw_button (&x, TITLE_7B, title, 0);
 	lcd_subdraw_divider(&x);
-	lcd_subdraw_button (&x, BUTTON_1X, name);
+	lcd_subdraw_button (&x, BUTTON_1X, name, 0);
 	lcd_subdraw_divider(&x);
 	
 	lcd_setup_drawing(LCD_MONO, x, 511, 3, 4);
 	
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_A);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_A, selected == 0);
 	lcd_subdraw_lowdivider(&x);
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_B);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_B, selected == 1);
 	lcd_subdraw_lowdivider(&x);
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_C);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_C, selected == 2);
 	lcd_subdraw_lowdivider(&x);
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_D);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_D, selected == 3);
 	lcd_subdraw_lowdivider(&x);
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_E);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_E, selected == 4);
 	lcd_subdraw_lowdivider(&x);
-	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_F);
+	lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_F, selected == 5);
 	
 	lcd_draw_name_list(list);
 	
diff --git a/lcd.h b/lcd.h
index f136ead..a62c361 100644
--- a/lcd.h
+++ b/lcd.h
@@ -1,6 +1,6 @@
 /* LCD */
 /*
-Copyright 2021 Balthasar Szczepański
+Copyright 2021, 2025 Balthasar Szczepański
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
@@ -428,12 +428,14 @@ void        lcd_draw_adsr (const uint8_t * const data);
 void        lcd_subdraw_button (
 	uint16_t * const x,
 	const uint8_t type,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
 );
 void        lcd_subdraw_lowbutton8 (
 	uint16_t * const x,
 	const uint8_t type,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
 );
 void        lcd_subdraw_lowbutton16 (
 	uint16_t * const x,
@@ -450,11 +452,18 @@ void        lcd_draw_menu (
 	const uint8_t * const button_C,
 	const uint8_t * const button_D,
 	const uint8_t * const button_E,
- 	const uint8_t * const button_F
+	const uint8_t * const button_F,
+	const int8_t          selected
 );
+void        lcd_update_title (const uint8_t * const text);
 void        lcd_update_button (
 	const int8_t id,
-	const uint8_t * const text
+	const uint8_t * const text,
+	const uint8_t selected
+);
+void        lcd_select_button (
+	const int8_t id,
+	const uint8_t selected
 );
 void lcd_draw_name_cursor(const uint8_t pos);
 void lcd_erase_name_cursor(const uint8_t pos);
@@ -469,5 +478,6 @@ void lcd_draw_name_menu (
 	const uint8_t * const button_C,
 	const uint8_t * const button_D,
 	const uint8_t * const button_E,
-	const uint8_t * const button_F
+	const uint8_t * const button_F,
+	const int8_t          selected
 );
-- 
2.30.2