/* options.c: options dialog boxes
   Copyright (c) 2001-2013 Philip Kendall

   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
   (at your option) 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.

   Author contact information:

   E-mail: philip-fuse@shadowmagic.org.uk

*/

/* This file is autogenerated from options.dat by options.pl.
   Do not edit unless you know what you're doing! */

#include "config.h"

#ifdef USE_WIDGET

#include <stdio.h>
#include <string.h>

#include "display.h"
#include "fuse.h"
#include "options.h"
#include "options_internals.h"
#include "periph.h"
#include "ui/widget/widget_internals.h"
#include "ui/uidisplay.h"

struct widget_option_entry;

/* A generic click function */
typedef void (*widget_option_click_fn)( void );
typedef void (*widget_option_draw_fn)( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );

/* A general menu */
typedef struct widget_option_entry {
  const char *text;
  int index;
  input_key key;		/* Which key to activate this option */
  const char *suffix;
  const char * const *options;

  widget_option_click_fn click;
  widget_option_draw_fn draw;
} widget_option_entry;

static void
widget_combo_click( const char *title, const char * const *options, char **current, int def )
{
  int error, i;
  widget_select_t sel;

  sel.title = title;
  sel.options = options;
  sel.current = def;
  sel.finish_all = 0;
  for( i = 0; options[i] != NULL; i++ ) {
    if( *current != NULL && !strcmp( options[ i ], *current ) )
        sel.current = i;
  }
  sel.count = i;

  error = widget_do_select( &sel );

  if( !error && sel.result >= 0 ) {
    if( *current ) free( *current );
    *current = strdup( options[ sel.result ] );
  }
}

static int
option_enumerate_combo( const char * const *options, char *value, int def ) {
  int i;
  if( value != NULL ) {
    for( i = 0; options[i] != NULL; i++) {
      if( !strcmp( value, options[ i ] ) )
        return i;
    }
  }
  return def;
}

static const char * const widget_phantom_typist_mode_combo[] = {
  "Auto",
  "Keyword",
  "Keystroke",
  "Menu",
  "Plus 2A",
  "Plus 3",
  NULL
};

int
option_enumerate_media_phantom_typist_mode( void ) {
  return option_enumerate_combo( widget_phantom_typist_mode_combo,
				 settings_current.phantom_typist_mode,
				 0 );
}

static const char * const widget_stereo_ay_combo[] = {
  "None",
  "ACB",
  "ABC",
  NULL
};

int
option_enumerate_sound_stereo_ay( void ) {
  return option_enumerate_combo( widget_stereo_ay_combo,
				 settings_current.stereo_ay,
				 0 );
}

static const char * const widget_speaker_type_combo[] = {
  "TV speaker",
  "Beeper",
  "Unfiltered",
  NULL
};

int
option_enumerate_sound_speaker_type( void ) {
  return option_enumerate_combo( widget_speaker_type_combo,
				 settings_current.speaker_type,
				 0 );
}

static const char * const widget_drive_plus3a_type_combo[] = {
  "Single-sided 40 track",
  "Double-sided 40 track",
  "Single-sided 80 track",
  "Double-sided 80 track",
  NULL
};

int
option_enumerate_diskoptions_drive_plus3a_type( void ) {
  return option_enumerate_combo( widget_drive_plus3a_type_combo,
				 settings_current.drive_plus3a_type,
				 0 );
}

static const char * const widget_drive_plus3b_type_combo[] = {
  "Disabled",
  "Single-sided 40 track",
  "Double-sided 40 track",
  "Single-sided 80 track",
  "Double-sided 80 track",
  NULL
};

int
option_enumerate_diskoptions_drive_plus3b_type( void ) {
  return option_enumerate_combo( widget_drive_plus3b_type_combo,
				 settings_current.drive_plus3b_type,
				 4 );
}

#define widget_drive_beta128a_type_combo widget_drive_plus3a_type_combo

int
option_enumerate_diskoptions_drive_beta128a_type( void ) {
  return option_enumerate_combo( widget_drive_beta128a_type_combo,
				 settings_current.drive_beta128a_type,
				 3 );
}

#define widget_drive_beta128b_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_beta128b_type( void ) {
  return option_enumerate_combo( widget_drive_beta128b_type_combo,
				 settings_current.drive_beta128b_type,
				 4 );
}

#define widget_drive_beta128c_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_beta128c_type( void ) {
  return option_enumerate_combo( widget_drive_beta128c_type_combo,
				 settings_current.drive_beta128c_type,
				 4 );
}

#define widget_drive_beta128d_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_beta128d_type( void ) {
  return option_enumerate_combo( widget_drive_beta128d_type_combo,
				 settings_current.drive_beta128d_type,
				 4 );
}

#define widget_drive_plusd1_type_combo widget_drive_plus3a_type_combo

int
option_enumerate_diskoptions_drive_plusd1_type( void ) {
  return option_enumerate_combo( widget_drive_plusd1_type_combo,
				 settings_current.drive_plusd1_type,
				 3 );
}

#define widget_drive_plusd2_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_plusd2_type( void ) {
  return option_enumerate_combo( widget_drive_plusd2_type_combo,
				 settings_current.drive_plusd2_type,
				 4 );
}

#define widget_drive_didaktik80a_type_combo widget_drive_plus3a_type_combo

int
option_enumerate_diskoptions_drive_didaktik80a_type( void ) {
  return option_enumerate_combo( widget_drive_didaktik80a_type_combo,
				 settings_current.drive_didaktik80a_type,
				 3 );
}

#define widget_drive_didaktik80b_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_didaktik80b_type( void ) {
  return option_enumerate_combo( widget_drive_didaktik80b_type_combo,
				 settings_current.drive_didaktik80b_type,
				 4 );
}

#define widget_drive_disciple1_type_combo widget_drive_plus3a_type_combo

int
option_enumerate_diskoptions_drive_disciple1_type( void ) {
  return option_enumerate_combo( widget_drive_disciple1_type_combo,
				 settings_current.drive_disciple1_type,
				 3 );
}

#define widget_drive_disciple2_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_disciple2_type( void ) {
  return option_enumerate_combo( widget_drive_disciple2_type_combo,
				 settings_current.drive_disciple2_type,
				 4 );
}

#define widget_drive_opus1_type_combo widget_drive_plus3a_type_combo

int
option_enumerate_diskoptions_drive_opus1_type( void ) {
  return option_enumerate_combo( widget_drive_opus1_type_combo,
				 settings_current.drive_opus1_type,
				 0 );
}

#define widget_drive_opus2_type_combo widget_drive_plus3b_type_combo

int
option_enumerate_diskoptions_drive_opus2_type( void ) {
  return option_enumerate_combo( widget_drive_opus2_type_combo,
				 settings_current.drive_opus2_type,
				 1 );
}

static const char * const widget_disk_try_merge_combo[] = {
  "Never",
  "With single-sided drives",
  "Always",
  NULL
};

int
option_enumerate_diskoptions_disk_try_merge( void ) {
  return option_enumerate_combo( widget_disk_try_merge_combo,
				 settings_current.disk_try_merge,
				 1 );
}

static const char * const widget_movie_compr_combo[] = {
  "None",
  "Lossless",
  "High",
  NULL
};

int
option_enumerate_movie_movie_compr( void ) {
  return option_enumerate_combo( widget_movie_compr_combo,
				 settings_current.movie_compr,
				 1 );
}

static int  widget_general_running = 0;
static void widget_emulation_speed_click( void );
static void widget_option_emulation_speed_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_frame_rate_click( void );
static void widget_option_frame_rate_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_issue2_click( void );
static void widget_option_issue2_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_recreated_spectrum_click( void );
static void widget_option_recreated_spectrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_keyboard_arrows_shifted_click( void );
static void widget_option_keyboard_arrows_shifted_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_writable_roms_click( void );
static void widget_option_writable_roms_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_late_timings_click( void );
static void widget_option_late_timings_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_z80_is_cmos_click( void );
static void widget_option_z80_is_cmos_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_rs232_handshake_click( void );
static void widget_option_rs232_handshake_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_bw_tv_click( void );
static void widget_option_bw_tv_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_pal_tv2x_click( void );
static void widget_option_pal_tv2x_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_full_screen_click( void );
static void widget_option_full_screen_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_statusbar_click( void );
static void widget_option_statusbar_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_joy_prompt_click( void );
static void widget_option_joy_prompt_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_confirm_actions_click( void );
static void widget_option_confirm_actions_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_autosave_settings_click( void );
static void widget_option_autosave_settings_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_media_running = 0;
static void widget_auto_load_click( void );
static void widget_option_auto_load_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_phantom_typist_mode_click( void );
static void widget_option_phantom_typist_mode_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_detect_loader_click( void );
static void widget_option_detect_loader_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_fastload_click( void );
static void widget_option_fastload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_tape_traps_click( void );
static void widget_option_tape_traps_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_accelerate_loader_click( void );
static void widget_option_accelerate_loader_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_slt_traps_click( void );
static void widget_option_slt_traps_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_mdr_len_click( void );
static void widget_option_mdr_len_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_mdr_random_len_click( void );
static void widget_option_mdr_random_len_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_peripherals_general_running = 0;
static void widget_joy_kempston_click( void );
static void widget_option_joy_kempston_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_kempston_mouse_click( void );
static void widget_option_kempston_mouse_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_mouse_swap_buttons_click( void );
static void widget_option_mouse_swap_buttons_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_interface1_click( void );
static void widget_option_interface1_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_interface2_click( void );
static void widget_option_interface2_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_multiface1_click( void );
static void widget_option_multiface1_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_multiface128_click( void );
static void widget_option_multiface128_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_multiface3_click( void );
static void widget_option_multiface3_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_multiface1_stealth_click( void );
static void widget_option_multiface1_stealth_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_printer_click( void );
static void widget_option_printer_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxprinter_click( void );
static void widget_option_zxprinter_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_speccyboot_click( void );
static void widget_option_speccyboot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_spectranet_click( void );
static void widget_option_spectranet_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_spectranet_disable_click( void );
static void widget_option_spectranet_disable_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_ttx2000s_click( void );
static void widget_option_ttx2000s_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_usource_click( void );
static void widget_option_usource_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_peripherals_sound_running = 0;
static void widget_fuller_click( void );
static void widget_option_fuller_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_melodik_click( void );
static void widget_option_melodik_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_specdrum_click( void );
static void widget_option_specdrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_covox_click( void );
static void widget_option_covox_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_uspeech_click( void );
static void widget_option_uspeech_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_peripherals_disk_running = 0;
static void widget_simpleide_active_click( void );
static void widget_option_simpleide_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxatasp_active_click( void );
static void widget_option_zxatasp_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxatasp_upload_click( void );
static void widget_option_zxatasp_upload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxatasp_wp_click( void );
static void widget_option_zxatasp_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxcf_active_click( void );
static void widget_option_zxcf_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxcf_upload_click( void );
static void widget_option_zxcf_upload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_divide_enabled_click( void );
static void widget_option_divide_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_divide_wp_click( void );
static void widget_option_divide_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_divmmc_enabled_click( void );
static void widget_option_divmmc_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_divmmc_wp_click( void );
static void widget_option_divmmc_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_plusd_click( void );
static void widget_option_plusd_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_didaktik80_click( void );
static void widget_option_didaktik80_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_disciple_click( void );
static void widget_option_disciple_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_beta128_click( void );
static void widget_option_beta128_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_beta128_48boot_click( void );
static void widget_option_beta128_48boot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_opus_click( void );
static void widget_option_opus_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_zxmmc_enabled_click( void );
static void widget_option_zxmmc_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_rzx_running = 0;
static void widget_rzx_autosaves_click( void );
static void widget_option_rzx_autosaves_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_rzx_compression_click( void );
static void widget_option_rzx_compression_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_competition_mode_click( void );
static void widget_option_competition_mode_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_competition_code_click( void );
static void widget_option_competition_code_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_embed_snapshot_click( void );
static void widget_option_embed_snapshot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_sound_running = 0;
static void widget_sound_click( void );
static void widget_option_sound_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_sound_load_click( void );
static void widget_option_sound_load_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_stereo_ay_click( void );
static void widget_option_stereo_ay_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_sound_force_8bit_click( void );
static void widget_option_sound_force_8bit_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_speaker_type_click( void );
static void widget_option_speaker_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_volume_ay_click( void );
static void widget_option_volume_ay_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_volume_beeper_click( void );
static void widget_option_volume_beeper_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_volume_specdrum_click( void );
static void widget_option_volume_specdrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_volume_covox_click( void );
static void widget_option_volume_covox_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_volume_uspeech_click( void );
static void widget_option_volume_uspeech_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_diskoptions_running = 0;
static void widget_drive_plus3a_type_click( void );
static void widget_option_drive_plus3a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_plus3b_type_click( void );
static void widget_option_drive_plus3b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_plus3_detect_speedlock_click( void );
static void widget_option_plus3_detect_speedlock_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_beta128a_type_click( void );
static void widget_option_drive_beta128a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_beta128b_type_click( void );
static void widget_option_drive_beta128b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_beta128c_type_click( void );
static void widget_option_drive_beta128c_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_beta128d_type_click( void );
static void widget_option_drive_beta128d_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_plusd1_type_click( void );
static void widget_option_drive_plusd1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_plusd2_type_click( void );
static void widget_option_drive_plusd2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_didaktik80a_type_click( void );
static void widget_option_drive_didaktik80a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_didaktik80b_type_click( void );
static void widget_option_drive_didaktik80b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_disciple1_type_click( void );
static void widget_option_drive_disciple1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_disciple2_type_click( void );
static void widget_option_drive_disciple2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_opus1_type_click( void );
static void widget_option_drive_opus1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_drive_opus2_type_click( void );
static void widget_option_drive_opus2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_disk_try_merge_click( void );
static void widget_option_disk_try_merge_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_disk_ask_merge_click( void );
static void widget_option_disk_ask_merge_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static int  widget_movie_running = 0;
static void widget_movie_compr_click( void );
static void widget_option_movie_compr_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );
static void widget_movie_stop_after_rzx_click( void );
static void widget_option_movie_stop_after_rzx_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show );

static widget_option_entry options_general[] = {
  { "General Options" },
  { "\012E\001mulation speed", 0, INPUT_KEY_e, "%", NULL, widget_emulation_speed_click, widget_option_emulation_speed_draw },
  { "F\012r\001ame rate (1:n)", 1, INPUT_KEY_r, "frames", NULL, widget_frame_rate_click, widget_option_frame_rate_draw },
  { "Issue \0122\001 keyboard", 2, INPUT_KEY_2, NULL, NULL, widget_issue2_click, widget_option_issue2_draw },
  { "Recrea\012t\001ed ZX Spectrum", 3, INPUT_KEY_t, NULL, NULL, widget_recreated_spectrum_click, widget_option_recreated_spectrum_draw },
  { "Use shift with \012a\001rrow keys", 4, INPUT_KEY_a, NULL, NULL, widget_keyboard_arrows_shifted_click, widget_option_keyboard_arrows_shifted_draw },
  { "Allow \012w\001rites to ROM", 5, INPUT_KEY_w, NULL, NULL, widget_writable_roms_click, widget_option_writable_roms_draw },
  { "Late t\012i\001mings", 6, INPUT_KEY_i, NULL, NULL, widget_late_timings_click, widget_option_late_timings_draw },
  { "\012Z\00180 is CMOS", 7, INPUT_KEY_z, NULL, NULL, widget_z80_is_cmos_click, widget_option_z80_is_cmos_draw },
  { "RS-232 \012h\001andshake", 8, INPUT_KEY_h, NULL, NULL, widget_rs232_handshake_click, widget_option_rs232_handshake_draw },
  { "Black and white T\012V\001", 9, INPUT_KEY_v, NULL, NULL, widget_bw_tv_click, widget_option_bw_tv_draw },
  { "\012P\001AL-TV use TV2x effect", 10, INPUT_KEY_p, NULL, NULL, widget_pal_tv2x_click, widget_option_pal_tv2x_draw },
  { "Full \012s\001creen", 11, INPUT_KEY_s, NULL, NULL, widget_full_screen_click, widget_option_full_screen_draw },
  { "Show status\012b\001ar", 12, INPUT_KEY_b, NULL, NULL, widget_statusbar_click, widget_option_statusbar_draw },
  { "Snap \012j\001oystick prompt", 13, INPUT_KEY_j, NULL, NULL, widget_joy_prompt_click, widget_option_joy_prompt_draw },
  { "\012C\001onfirm actions", 14, INPUT_KEY_c, NULL, NULL, widget_confirm_actions_click, widget_option_confirm_actions_draw },
  { "A\012u\001to-save settings", 15, INPUT_KEY_u, NULL, NULL, widget_autosave_settings_click, widget_option_autosave_settings_draw },
  { NULL }
};

static widget_option_entry options_media[] = {
  { "Media Options" },
  { "\012A\001uto-load media", 0, INPUT_KEY_a, NULL, NULL, widget_auto_load_click, widget_option_auto_load_draw },
  { "\012P\001hantom typist mode", 1, INPUT_KEY_p, NULL, widget_phantom_typist_mode_combo, widget_phantom_typist_mode_click, widget_option_phantom_typist_mode_draw },
  { "\012D\001etect loaders", 2, INPUT_KEY_d, NULL, NULL, widget_detect_loader_click, widget_option_detect_loader_draw },
  { "\012F\001astloading", 3, INPUT_KEY_f, NULL, NULL, widget_fastload_click, widget_option_fastload_draw },
  { "Use \012t\001ape traps", 4, INPUT_KEY_t, NULL, NULL, widget_tape_traps_click, widget_option_tape_traps_draw },
  { "Accelerate l\012o\001aders", 5, INPUT_KEY_o, NULL, NULL, widget_accelerate_loader_click, widget_option_accelerate_loader_draw },
  { "Use .s\012l\001t traps", 6, INPUT_KEY_l, NULL, NULL, widget_slt_traps_click, widget_option_slt_traps_draw },
  { "\012M\001DR cartridge len", 7, INPUT_KEY_m, "blocks", NULL, widget_mdr_len_click, widget_option_mdr_len_draw },
  { "Random len\012g\001th MDR cartridge", 8, INPUT_KEY_g, NULL, NULL, widget_mdr_random_len_click, widget_option_mdr_random_len_draw },
  { NULL }
};

static widget_option_entry options_peripherals_general[] = {
  { "General Peripheral Options" },
  { "\012K\001empston joystick", 0, INPUT_KEY_k, NULL, NULL, widget_joy_kempston_click, widget_option_joy_kempston_draw },
  { "Kempston \012m\001ouse", 1, INPUT_KEY_m, NULL, NULL, widget_kempston_mouse_click, widget_option_kempston_mouse_draw },
  { "\012S\001wap mouse buttons", 2, INPUT_KEY_s, NULL, NULL, widget_mouse_swap_buttons_click, widget_option_mouse_swap_buttons_draw },
  { "\012I\001nterface 1", 3, INPUT_KEY_i, NULL, NULL, widget_interface1_click, widget_option_interface1_draw },
  { "In\012t\001erface 2", 4, INPUT_KEY_t, NULL, NULL, widget_interface2_click, widget_option_interface2_draw },
  { "Mu\012l\001tiface One", 5, INPUT_KEY_l, NULL, NULL, widget_multiface1_click, widget_option_multiface1_draw },
  { "Multiface 12\0128\001", 6, INPUT_KEY_8, NULL, NULL, widget_multiface128_click, widget_option_multiface128_draw },
  { "Multiface \0123\001", 7, INPUT_KEY_3, NULL, NULL, widget_multiface3_click, widget_option_multiface3_draw },
  { "Stealt\012h\001 Multiface One", 8, INPUT_KEY_h, NULL, NULL, widget_multiface1_stealth_click, widget_option_multiface1_stealth_draw },
  { "Emulate \012p\001rinters", 9, INPUT_KEY_p, NULL, NULL, widget_printer_click, widget_option_printer_draw },
  { "\012Z\001X Printer", 10, INPUT_KEY_z, NULL, NULL, widget_zxprinter_click, widget_option_zxprinter_draw },
  { "Speccy\012B\001oot interface", 11, INPUT_KEY_b, NULL, NULL, widget_speccyboot_click, widget_option_speccyboot_draw },
  { "Spectra\012n\001et", 12, INPUT_KEY_n, NULL, NULL, widget_spectranet_click, widget_option_spectranet_draw },
  { "Spe\012c\001tranet disable", 13, INPUT_KEY_c, NULL, NULL, widget_spectranet_disable_click, widget_option_spectranet_disable_draw },
  { "TT\012X\0012000S", 14, INPUT_KEY_x, NULL, NULL, widget_ttx2000s_click, widget_option_ttx2000s_draw },
  { "uSo\012u\001rce", 15, INPUT_KEY_u, NULL, NULL, widget_usource_click, widget_option_usource_draw },
  { NULL }
};

static widget_option_entry options_peripherals_sound[] = {
  { "Sound Peripheral Options" },
  { "\012F\001uller Box", 0, INPUT_KEY_f, NULL, NULL, widget_fuller_click, widget_option_fuller_draw },
  { "M\012e\001lodik", 1, INPUT_KEY_e, NULL, NULL, widget_melodik_click, widget_option_melodik_draw },
  { "Spec\012D\001rum interface", 2, INPUT_KEY_d, NULL, NULL, widget_specdrum_click, widget_option_specdrum_draw },
  { "C\012o\001vox interface", 3, INPUT_KEY_o, NULL, NULL, widget_covox_click, widget_option_covox_draw },
  { "\012u\001Speech", 4, INPUT_KEY_u, NULL, NULL, widget_uspeech_click, widget_option_uspeech_draw },
  { NULL }
};

static widget_option_entry options_peripherals_disk[] = {
  { "Disk Peripheral Options" },
  { "Simple \0128\001-bit IDE", 0, INPUT_KEY_8, NULL, NULL, widget_simpleide_active_click, widget_option_simpleide_active_draw },
  { "\012Z\001XATASP interface", 1, INPUT_KEY_z, NULL, NULL, widget_zxatasp_active_click, widget_option_zxatasp_active_draw },
  { "ZXATASP up\012l\001oad", 2, INPUT_KEY_l, NULL, NULL, widget_zxatasp_upload_click, widget_option_zxatasp_upload_draw },
  { "Z\012X\001ATASP write protect", 3, INPUT_KEY_x, NULL, NULL, widget_zxatasp_wp_click, widget_option_zxatasp_wp_draw },
  { "ZX\012C\001F interface", 4, INPUT_KEY_c, NULL, NULL, widget_zxcf_active_click, widget_option_zxcf_active_draw },
  { "ZXCF \012u\001pload", 5, INPUT_KEY_u, NULL, NULL, widget_zxcf_upload_click, widget_option_zxcf_upload_draw },
  { "Div\012I\001DE interface", 6, INPUT_KEY_i, NULL, NULL, widget_divide_enabled_click, widget_option_divide_enabled_draw },
  { "DivIDE \012w\001rite protect", 7, INPUT_KEY_w, NULL, NULL, widget_divide_wp_click, widget_option_divide_wp_draw },
  { "Div\012M\001MC interface", 8, INPUT_KEY_m, NULL, NULL, widget_divmmc_enabled_click, widget_option_divmmc_enabled_draw },
  { "DivMMC w\012r\001ite protect", 9, INPUT_KEY_r, NULL, NULL, widget_divmmc_wp_click, widget_option_divmmc_wp_draw },
  { "+\012D\001 interface", 10, INPUT_KEY_d, NULL, NULL, widget_plusd_click, widget_option_plusd_draw },
  { "Dida\012k\001tik 80 interface", 11, INPUT_KEY_k, NULL, NULL, widget_didaktik80_click, widget_option_didaktik80_draw },
  { "DISCi\012P\001LE interf(a)ce", 12, INPUT_KEY_p, NULL, NULL, widget_disciple_click, widget_option_disciple_draw },
  { "\012B\001eta 128 interface", 13, INPUT_KEY_b, NULL, NULL, widget_beta128_click, widget_option_beta128_draw },
  { "Beta 128 \012a\001uto-boot in 48K machines", 14, INPUT_KEY_a, NULL, NULL, widget_beta128_48boot_click, widget_option_beta128_48boot_draw },
  { "\012O\001pus Discovery interface", 15, INPUT_KEY_o, NULL, NULL, widget_opus_click, widget_option_opus_draw },
  { "ZXMMC i\012n\001terface", 16, INPUT_KEY_n, NULL, NULL, widget_zxmmc_enabled_click, widget_option_zxmmc_enabled_draw },
  { NULL }
};

static widget_option_entry options_rzx[] = {
  { "RZX Options" },
  { "Create \012a\001utosaves", 0, INPUT_KEY_a, NULL, NULL, widget_rzx_autosaves_click, widget_option_rzx_autosaves_draw },
  { "\012C\001ompress RZX data", 1, INPUT_KEY_c, NULL, NULL, widget_rzx_compression_click, widget_option_rzx_compression_draw },
  { "C\012o\001mpetition mode", 2, INPUT_KEY_o, NULL, NULL, widget_competition_mode_click, widget_option_competition_mode_draw },
  { "Co\012m\001petition code", 3, INPUT_KEY_m, "", NULL, widget_competition_code_click, widget_option_competition_code_draw },
  { "Always \012e\001mbed snapshot", 4, INPUT_KEY_e, NULL, NULL, widget_embed_snapshot_click, widget_option_embed_snapshot_draw },
  { NULL }
};

static widget_option_entry options_sound[] = {
  { "Sound Options" },
  { "\012S\001ound enabled", 0, INPUT_KEY_s, NULL, NULL, widget_sound_click, widget_option_sound_draw },
  { "\012L\001oading sound", 1, INPUT_KEY_l, NULL, NULL, widget_sound_load_click, widget_option_sound_load_draw },
  { "\012A\001Y stereo separation", 2, INPUT_KEY_a, NULL, widget_stereo_ay_combo, widget_stereo_ay_click, widget_option_stereo_ay_draw },
  { "\012F\001orce 8-bit", 3, INPUT_KEY_f, NULL, NULL, widget_sound_force_8bit_click, widget_option_sound_force_8bit_draw },
  { "Speaker \012t\001ype", 4, INPUT_KEY_t, NULL, widget_speaker_type_combo, widget_speaker_type_click, widget_option_speaker_type_draw },
  { "A\012Y\001 volume", 5, INPUT_KEY_y, "%", NULL, widget_volume_ay_click, widget_option_volume_ay_draw },
  { "B\012e\001eper volume", 6, INPUT_KEY_e, "%", NULL, widget_volume_beeper_click, widget_option_volume_beeper_draw },
  { "Spec\012D\001rum volume", 7, INPUT_KEY_d, "%", NULL, widget_volume_specdrum_click, widget_option_volume_specdrum_draw },
  { "\012C\001ovox volume", 8, INPUT_KEY_c, "%", NULL, widget_volume_covox_click, widget_option_volume_covox_draw },
  { "\012u\001Speech volume", 9, INPUT_KEY_u, "%", NULL, widget_volume_uspeech_click, widget_option_volume_uspeech_draw },
  { NULL }
};

static widget_option_entry options_diskoptions[] = {
  { "Drives Setup" },
  { "+\0123\001 Drive A", 0, INPUT_KEY_3, NULL, widget_drive_plus3a_type_combo, widget_drive_plus3a_type_click, widget_option_drive_plus3a_type_draw },
  { "+3 Driv\012e\001 B", 1, INPUT_KEY_e, NULL, widget_drive_plus3b_type_combo, widget_drive_plus3b_type_click, widget_option_drive_plus3b_type_draw },
  { "+3 Detect \012S\001peedlock", 2, INPUT_KEY_s, NULL, NULL, widget_plus3_detect_speedlock_click, widget_option_plus3_detect_speedlock_draw },
  { "Beta 128 Drive \012A\001", 3, INPUT_KEY_a, NULL, widget_drive_beta128a_type_combo, widget_drive_beta128a_type_click, widget_option_drive_beta128a_type_draw },
  { "Beta 128 Drive \012B\001", 4, INPUT_KEY_b, NULL, widget_drive_beta128b_type_combo, widget_drive_beta128b_type_click, widget_option_drive_beta128b_type_draw },
  { "Beta 128 Drive \012C\001", 5, INPUT_KEY_c, NULL, widget_drive_beta128c_type_combo, widget_drive_beta128c_type_click, widget_option_drive_beta128c_type_draw },
  { "Beta 128 Drive \012D\001", 6, INPUT_KEY_d, NULL, widget_drive_beta128d_type_combo, widget_drive_beta128d_type_click, widget_option_drive_beta128d_type_draw },
  { "+D Drive \0121\001", 7, INPUT_KEY_1, NULL, widget_drive_plusd1_type_combo, widget_drive_plusd1_type_click, widget_option_drive_plusd1_type_draw },
  { "+D Drive \0122\001", 8, INPUT_KEY_2, NULL, widget_drive_plusd2_type_combo, widget_drive_plusd2_type_click, widget_option_drive_plusd2_type_draw },
  { "Didaktik \0128\0010 Drive A", 9, INPUT_KEY_8, NULL, widget_drive_didaktik80a_type_combo, widget_drive_didaktik80a_type_click, widget_option_drive_didaktik80a_type_draw },
  { "Dida\012k\001tik 80 Drive B", 10, INPUT_KEY_k, NULL, widget_drive_didaktik80b_type_combo, widget_drive_didaktik80b_type_click, widget_option_drive_didaktik80b_type_draw },
  { "DI\012S\001CiPLE Drive 1", 11, INPUT_KEY_s, NULL, widget_drive_disciple1_type_combo, widget_drive_disciple1_type_click, widget_option_drive_disciple1_type_draw },
  { "DISCiP\012L\001E Drive 2", 12, INPUT_KEY_l, NULL, widget_drive_disciple2_type_combo, widget_drive_disciple2_type_click, widget_option_drive_disciple2_type_draw },
  { "\012O\001pus Drive 1", 13, INPUT_KEY_o, NULL, widget_drive_opus1_type_combo, widget_drive_opus1_type_click, widget_option_drive_opus1_type_draw },
  { "O\012p\001us Drive 2", 14, INPUT_KEY_p, NULL, widget_drive_opus2_type_combo, widget_drive_opus2_type_click, widget_option_drive_opus2_type_draw },
  { "\012T\001ry merge 'B' side of disks", 15, INPUT_KEY_t, NULL, widget_disk_try_merge_combo, widget_disk_try_merge_click, widget_option_disk_try_merge_draw },
  { "Con\012f\001irm merge disk sides", 16, INPUT_KEY_f, NULL, NULL, widget_disk_ask_merge_click, widget_option_disk_ask_merge_draw },
  { NULL }
};

static widget_option_entry options_movie[] = {
  { "Movie Options" },
  { "Movie \012c\001ompression", 0, INPUT_KEY_c, NULL, widget_movie_compr_combo, widget_movie_compr_click, widget_option_movie_compr_draw },
  { "\012S\001top recording after RZX ends", 1, INPUT_KEY_S, NULL, NULL, widget_movie_stop_after_rzx_click, widget_option_movie_stop_after_rzx_draw },
  { NULL }
};

static size_t highlight_line = 0;

/* General functions used by the options dialogs */
settings_info widget_options_settings;
int widget_options_print_option( int left_edge, int width, int number, const char* string, int value );
int widget_options_print_value( int left_edge, int width, int number, int value );
int widget_options_print_entry( int left_edge, int width, int number, const char *prefix, int value,
				const char *suffix );
int widget_options_print_combo( int left_edge, int width, int number, const char *prefix,
				const char * const *options, const char *value, int def );

static int widget_options_print_label( int left_edge, int width, int number, const char *string );
static int widget_options_print_data( int left_edge, int menu_width, int number, const char *string, int tcolor );
static int widget_calculate_option_width(widget_option_entry *menu);

static int
widget_options_show_all( widget_option_entry *options, settings_info *show )
{
  widget_option_entry *ptr;
  size_t height = 0;
  int menu_width = widget_calculate_option_width( options );
  int menu_left_edge_x;

  /* How many options do we have? */
  for( ptr = &options[1]; ptr->text; ptr++ )
    height ++;

  menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  /* Draw the dialog box */
  widget_dialog_with_border( menu_left_edge_x, 2, menu_width, 2 + height );

  widget_printstring( menu_left_edge_x*8+2, 16, WIDGET_COLOUR_TITLE, options->text );

  for( ptr = &options[1]; ptr->text; ptr++ ) {
    ptr->draw( menu_left_edge_x, menu_width, ptr, show );
  }

  widget_display_lines( 2, 2 + height );

  return 0;
}

int
widget_options_print_option( int left_edge, int width, int number, const char* string, int value )
{
  widget_options_print_label( left_edge, width, number, string );
  widget_options_print_value( left_edge, width, number, value );
  return 0;
}

static int
widget_options_print_label( int left_edge, int width, int number, const char *string )
{
  char buffer[128];
  size_t l, w;
  int colour = WIDGET_COLOUR_BACKGROUND;

  if( number == highlight_line ) colour = WIDGET_COLOUR_HIGHLIGHT;
  widget_rectangle( left_edge*8+1, number*8+24, width*8-2, 1*8, colour );

  snprintf( buffer, sizeof( buffer ), "%s", string );
  l = strlen( buffer );

  if( l >= sizeof( buffer ) )
    l = sizeof( buffer ) - 1;
  while( ( w = widget_substringwidth( string, l ) ) >= (left_edge+width-2)*8 )
    --l;
  buffer[l] = '\0';
  w = widget_printstring( left_edge*8+8, number*8+24, WIDGET_COLOUR_FOREGROUND, buffer )
      - 1;
  while ((w += 3) < (left_edge+width-1)*8-2)
    widget_putpixel (w, number*8+31, 0);
  return 0;
}

int
widget_options_print_value( int left_edge, int width, int number, int value )
{
  int colour = WIDGET_COLOUR_BACKGROUND;
  int x = (left_edge+width-2)*8-2;
  int y = number * 8 + 24;

  if( number == highlight_line ) colour = WIDGET_COLOUR_HIGHLIGHT;
  widget_rectangle( x, y, 8, 8, colour );
  widget_print_checkbox( x, y, colour, value );
  widget_display_rasters( y, 8 );
  return 0;
}

static int
widget_options_print_data( int left_edge, int menu_width, int number, const char *string, int tcolor )
{
  int colour = WIDGET_COLOUR_BACKGROUND;
  size_t width = widget_stringwidth( string );
  int x = (left_edge + menu_width-1)*8 - width - 2;
  int y = number * 8 + 24;

  if( number == highlight_line ) colour = WIDGET_COLOUR_HIGHLIGHT;
  widget_rectangle( x, y, width, 8, colour );
  widget_printstring( x, y, tcolor, string );
  widget_display_rasters( y, 8 );

  return 0;
}

int
widget_options_print_entry( int left_edge, int width, int number, const char *prefix, int value,
			    const char *suffix )
{
  char buffer[128];
  widget_options_print_label( left_edge, width, number, prefix );
  snprintf( buffer, sizeof( buffer ), "%d %s", value, suffix );
  return widget_options_print_data( left_edge, width, number, buffer, WIDGET_COLOUR_FOREGROUND );
}

int
widget_options_print_combo( int left_edge, int width, int number, const char *prefix,
			    const char * const *option, const char *value, int def )
{
  int i = 0;
  const char *c;
  char buffer[64];

  c = option[ def ];
  if( value != NULL ) {
    while( option[ i ] != NULL ) {
      if( !strcmp( option[ i ], value ) )
        c = option[ i ];
      i++;
    }
  }
  widget_options_print_label( left_edge, width, number, prefix );
  snprintf( buffer, sizeof( buffer ), "%s", c );
  return widget_options_print_data( left_edge, width, number, buffer, WIDGET_COLOUR_DISABLED );
}

int
widget_options_finish( widget_finish_state finished )
{
  int error;
  int needs_hard_reset;

  /* If we exited normally, actually set the options */
  if( finished == WIDGET_FINISHED_OK ) {
    /* Get a copy of current settings */
    settings_info original_settings;
    memset( &original_settings, 0, sizeof( settings_info ) );
    settings_copy( &original_settings, &settings_current );

    /* Apply new options */
    settings_copy( &settings_current, &widget_options_settings );

    needs_hard_reset = periph_postcheck();

    if( needs_hard_reset ) {
      error = widget_do_query( "Some options need to reset the machine. Reset?" );
      if( !error && !widget_query.confirm )
        settings_copy( &settings_current, &original_settings );
      else
        periph_posthook();
    }
    else {
      /* Bring the peripherals list into sync with the new options */
      periph_posthook();
    }

    settings_free( &original_settings );

    /* make the needed UI changes */
    uidisplay_hotswap_gfx_mode();
  }
  settings_free( &widget_options_settings );
  memset( &widget_options_settings, 0, sizeof( settings_info ) );

  return 0;
}

const int options_vert_external_margin = 8;

static int
widget_calculate_option_width(widget_option_entry *menu)
{
  widget_option_entry *ptr;
  int max_width=0;

  if (!menu) {
    return 64;
  }

  max_width = widget_stringwidth( menu->text )+5*8;

  for( ptr = &menu[1]; ptr->text; ptr++ ) {
    int total_width = widget_stringwidth(ptr->text)+3*8;

    /* If this is a number format, leave room for 4 digits as well as the
       text */
    if( ptr->suffix ) total_width += widget_stringwidth(ptr->suffix)+4*8;
    if( ptr->options ) {
      int combo_width = 0;
      const char * const *options = ptr->options;
      while( *options != NULL ) {
        if( combo_width < widget_stringwidth( *options ) )
          combo_width = widget_stringwidth( *options );
        options++;
      }
      total_width += combo_width;
    }

    if (total_width > max_width)
      max_width = total_width;
  }

  return (max_width+options_vert_external_margin*2)/8;
}


int
widget_general_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_general_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_general_running = 1;
  }

  error = widget_options_show_all( options_general, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_emulation_speed_click( void )
{
  widget_text_t text_data;

  text_data.title = "Emulation speed";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 5;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.emulation_speed );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.emulation_speed = atoi( widget_text_text );
  }
}

static void
widget_option_emulation_speed_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->emulation_speed,
                              menu->suffix );
}

static void
widget_frame_rate_click( void )
{
  widget_text_t text_data;

  text_data.title = "Frame rate (1:n)";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 1;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.frame_rate );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.frame_rate = atoi( widget_text_text );
  }
}

static void
widget_option_frame_rate_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->frame_rate,
                              menu->suffix );
}

static void
widget_issue2_click( void )
{
  widget_options_settings.issue2 = ! widget_options_settings.issue2;
}

static void
widget_option_issue2_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->issue2 );
}

static void
widget_recreated_spectrum_click( void )
{
  widget_options_settings.recreated_spectrum = ! widget_options_settings.recreated_spectrum;
}

static void
widget_option_recreated_spectrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->recreated_spectrum );
}

static void
widget_keyboard_arrows_shifted_click( void )
{
  widget_options_settings.keyboard_arrows_shifted = ! widget_options_settings.keyboard_arrows_shifted;
}

static void
widget_option_keyboard_arrows_shifted_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->keyboard_arrows_shifted );
}

static void
widget_writable_roms_click( void )
{
  widget_options_settings.writable_roms = ! widget_options_settings.writable_roms;
}

static void
widget_option_writable_roms_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->writable_roms );
}

static void
widget_late_timings_click( void )
{
  widget_options_settings.late_timings = ! widget_options_settings.late_timings;
}

static void
widget_option_late_timings_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->late_timings );
}

static void
widget_z80_is_cmos_click( void )
{
  widget_options_settings.z80_is_cmos = ! widget_options_settings.z80_is_cmos;
}

static void
widget_option_z80_is_cmos_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->z80_is_cmos );
}

static void
widget_rs232_handshake_click( void )
{
  widget_options_settings.rs232_handshake = ! widget_options_settings.rs232_handshake;
}

static void
widget_option_rs232_handshake_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->rs232_handshake );
}

static void
widget_bw_tv_click( void )
{
  widget_options_settings.bw_tv = ! widget_options_settings.bw_tv;
}

static void
widget_option_bw_tv_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->bw_tv );
}

static void
widget_pal_tv2x_click( void )
{
  widget_options_settings.pal_tv2x = ! widget_options_settings.pal_tv2x;
}

static void
widget_option_pal_tv2x_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->pal_tv2x );
}

static void
widget_full_screen_click( void )
{
  widget_options_settings.full_screen = ! widget_options_settings.full_screen;
}

static void
widget_option_full_screen_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->full_screen );
}

static void
widget_statusbar_click( void )
{
  widget_options_settings.statusbar = ! widget_options_settings.statusbar;
}

static void
widget_option_statusbar_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->statusbar );
}

static void
widget_joy_prompt_click( void )
{
  widget_options_settings.joy_prompt = ! widget_options_settings.joy_prompt;
}

static void
widget_option_joy_prompt_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->joy_prompt );
}

static void
widget_confirm_actions_click( void )
{
  widget_options_settings.confirm_actions = ! widget_options_settings.confirm_actions;
}

static void
widget_option_confirm_actions_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->confirm_actions );
}

static void
widget_autosave_settings_click( void )
{
  widget_options_settings.autosave_settings = ! widget_options_settings.autosave_settings;
}

static void
widget_option_autosave_settings_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->autosave_settings );
}

void
widget_general_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_general);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 16 );
    widget_general_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_general_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 16 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 16 ) {
      new_highlight_line = 16 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_general[highlight_line+1].click();
    options_general[highlight_line+1].draw( menu_left_edge_x, menu_width, options_general + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_general_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_general[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_general + old_highlight_line + 1, &widget_options_settings );
    options_general[highlight_line+1].draw( menu_left_edge_x, menu_width, options_general + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_general[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_general[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_general + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_media_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_media_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_media_running = 1;
  }

  error = widget_options_show_all( options_media, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_auto_load_click( void )
{
  widget_options_settings.auto_load = ! widget_options_settings.auto_load;
}

static void
widget_option_auto_load_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->auto_load );
}

static void
widget_phantom_typist_mode_click( void )
{
  widget_combo_click( "Phantom typist mode", widget_phantom_typist_mode_combo,
				&widget_options_settings.phantom_typist_mode,
				0 );
}

static void
widget_option_phantom_typist_mode_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->phantom_typist_mode, 0 );
}

static void
widget_detect_loader_click( void )
{
  widget_options_settings.detect_loader = ! widget_options_settings.detect_loader;
}

static void
widget_option_detect_loader_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->detect_loader );
}

static void
widget_fastload_click( void )
{
  widget_options_settings.fastload = ! widget_options_settings.fastload;
}

static void
widget_option_fastload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->fastload );
}

static void
widget_tape_traps_click( void )
{
  widget_options_settings.tape_traps = ! widget_options_settings.tape_traps;
}

static void
widget_option_tape_traps_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->tape_traps );
}

static void
widget_accelerate_loader_click( void )
{
  widget_options_settings.accelerate_loader = ! widget_options_settings.accelerate_loader;
}

static void
widget_option_accelerate_loader_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->accelerate_loader );
}

static void
widget_slt_traps_click( void )
{
  widget_options_settings.slt_traps = ! widget_options_settings.slt_traps;
}

static void
widget_option_slt_traps_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->slt_traps );
}

static void
widget_mdr_len_click( void )
{
  widget_text_t text_data;

  text_data.title = "MDR cartridge len";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.mdr_len );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.mdr_len = atoi( widget_text_text );
  }
}

static void
widget_option_mdr_len_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->mdr_len,
                              menu->suffix );
}

static void
widget_mdr_random_len_click( void )
{
  widget_options_settings.mdr_random_len = ! widget_options_settings.mdr_random_len;
}

static void
widget_option_mdr_random_len_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->mdr_random_len );
}

void
widget_media_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_media);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 9 );
    widget_media_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_media_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 9 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 9 ) {
      new_highlight_line = 9 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_media[highlight_line+1].click();
    options_media[highlight_line+1].draw( menu_left_edge_x, menu_width, options_media + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_media_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_media[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_media + old_highlight_line + 1, &widget_options_settings );
    options_media[highlight_line+1].draw( menu_left_edge_x, menu_width, options_media + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_media[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_media[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_media + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_peripherals_general_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_peripherals_general_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_peripherals_general_running = 1;
  }

  error = widget_options_show_all( options_peripherals_general, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_joy_kempston_click( void )
{
  widget_options_settings.joy_kempston = ! widget_options_settings.joy_kempston;
}

static void
widget_option_joy_kempston_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->joy_kempston );
}

static void
widget_kempston_mouse_click( void )
{
  widget_options_settings.kempston_mouse = ! widget_options_settings.kempston_mouse;
}

static void
widget_option_kempston_mouse_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->kempston_mouse );
}

static void
widget_mouse_swap_buttons_click( void )
{
  widget_options_settings.mouse_swap_buttons = ! widget_options_settings.mouse_swap_buttons;
}

static void
widget_option_mouse_swap_buttons_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->mouse_swap_buttons );
}

static void
widget_interface1_click( void )
{
  widget_options_settings.interface1 = ! widget_options_settings.interface1;
}

static void
widget_option_interface1_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->interface1 );
}

static void
widget_interface2_click( void )
{
  widget_options_settings.interface2 = ! widget_options_settings.interface2;
}

static void
widget_option_interface2_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->interface2 );
}

static void
widget_multiface1_click( void )
{
  widget_options_settings.multiface1 = ! widget_options_settings.multiface1;
}

static void
widget_option_multiface1_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->multiface1 );
}

static void
widget_multiface128_click( void )
{
  widget_options_settings.multiface128 = ! widget_options_settings.multiface128;
}

static void
widget_option_multiface128_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->multiface128 );
}

static void
widget_multiface3_click( void )
{
  widget_options_settings.multiface3 = ! widget_options_settings.multiface3;
}

static void
widget_option_multiface3_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->multiface3 );
}

static void
widget_multiface1_stealth_click( void )
{
  widget_options_settings.multiface1_stealth = ! widget_options_settings.multiface1_stealth;
}

static void
widget_option_multiface1_stealth_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->multiface1_stealth );
}

static void
widget_printer_click( void )
{
  widget_options_settings.printer = ! widget_options_settings.printer;
}

static void
widget_option_printer_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->printer );
}

static void
widget_zxprinter_click( void )
{
  widget_options_settings.zxprinter = ! widget_options_settings.zxprinter;
}

static void
widget_option_zxprinter_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxprinter );
}

static void
widget_speccyboot_click( void )
{
  widget_options_settings.speccyboot = ! widget_options_settings.speccyboot;
}

static void
widget_option_speccyboot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->speccyboot );
}

static void
widget_spectranet_click( void )
{
  widget_options_settings.spectranet = ! widget_options_settings.spectranet;
}

static void
widget_option_spectranet_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->spectranet );
}

static void
widget_spectranet_disable_click( void )
{
  widget_options_settings.spectranet_disable = ! widget_options_settings.spectranet_disable;
}

static void
widget_option_spectranet_disable_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->spectranet_disable );
}

static void
widget_ttx2000s_click( void )
{
  widget_options_settings.ttx2000s = ! widget_options_settings.ttx2000s;
}

static void
widget_option_ttx2000s_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->ttx2000s );
}

static void
widget_usource_click( void )
{
  widget_options_settings.usource = ! widget_options_settings.usource;
}

static void
widget_option_usource_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->usource );
}

void
widget_peripherals_general_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_peripherals_general);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 16 );
    widget_peripherals_general_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_peripherals_general_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 16 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 16 ) {
      new_highlight_line = 16 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_peripherals_general[highlight_line+1].click();
    options_peripherals_general[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_general + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_peripherals_general_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_peripherals_general[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_general + old_highlight_line + 1, &widget_options_settings );
    options_peripherals_general[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_general + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_peripherals_general[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_peripherals_general[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_general + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_peripherals_sound_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_peripherals_sound_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_peripherals_sound_running = 1;
  }

  error = widget_options_show_all( options_peripherals_sound, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_fuller_click( void )
{
  widget_options_settings.fuller = ! widget_options_settings.fuller;
}

static void
widget_option_fuller_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->fuller );
}

static void
widget_melodik_click( void )
{
  widget_options_settings.melodik = ! widget_options_settings.melodik;
}

static void
widget_option_melodik_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->melodik );
}

static void
widget_specdrum_click( void )
{
  widget_options_settings.specdrum = ! widget_options_settings.specdrum;
}

static void
widget_option_specdrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->specdrum );
}

static void
widget_covox_click( void )
{
  widget_options_settings.covox = ! widget_options_settings.covox;
}

static void
widget_option_covox_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->covox );
}

static void
widget_uspeech_click( void )
{
  widget_options_settings.uspeech = ! widget_options_settings.uspeech;
}

static void
widget_option_uspeech_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->uspeech );
}

void
widget_peripherals_sound_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_peripherals_sound);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 5 );
    widget_peripherals_sound_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_peripherals_sound_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 5 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 5 ) {
      new_highlight_line = 5 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_peripherals_sound[highlight_line+1].click();
    options_peripherals_sound[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_sound + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_peripherals_sound_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_peripherals_sound[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_sound + old_highlight_line + 1, &widget_options_settings );
    options_peripherals_sound[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_sound + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_peripherals_sound[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_peripherals_sound[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_sound + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_peripherals_disk_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_peripherals_disk_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_peripherals_disk_running = 1;
  }

  error = widget_options_show_all( options_peripherals_disk, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_simpleide_active_click( void )
{
  widget_options_settings.simpleide_active = ! widget_options_settings.simpleide_active;
}

static void
widget_option_simpleide_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->simpleide_active );
}

static void
widget_zxatasp_active_click( void )
{
  widget_options_settings.zxatasp_active = ! widget_options_settings.zxatasp_active;
}

static void
widget_option_zxatasp_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxatasp_active );
}

static void
widget_zxatasp_upload_click( void )
{
  widget_options_settings.zxatasp_upload = ! widget_options_settings.zxatasp_upload;
}

static void
widget_option_zxatasp_upload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxatasp_upload );
}

static void
widget_zxatasp_wp_click( void )
{
  widget_options_settings.zxatasp_wp = ! widget_options_settings.zxatasp_wp;
}

static void
widget_option_zxatasp_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxatasp_wp );
}

static void
widget_zxcf_active_click( void )
{
  widget_options_settings.zxcf_active = ! widget_options_settings.zxcf_active;
}

static void
widget_option_zxcf_active_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxcf_active );
}

static void
widget_zxcf_upload_click( void )
{
  widget_options_settings.zxcf_upload = ! widget_options_settings.zxcf_upload;
}

static void
widget_option_zxcf_upload_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxcf_upload );
}

static void
widget_divide_enabled_click( void )
{
  widget_options_settings.divide_enabled = ! widget_options_settings.divide_enabled;
}

static void
widget_option_divide_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->divide_enabled );
}

static void
widget_divide_wp_click( void )
{
  widget_options_settings.divide_wp = ! widget_options_settings.divide_wp;
}

static void
widget_option_divide_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->divide_wp );
}

static void
widget_divmmc_enabled_click( void )
{
  widget_options_settings.divmmc_enabled = ! widget_options_settings.divmmc_enabled;
}

static void
widget_option_divmmc_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->divmmc_enabled );
}

static void
widget_divmmc_wp_click( void )
{
  widget_options_settings.divmmc_wp = ! widget_options_settings.divmmc_wp;
}

static void
widget_option_divmmc_wp_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->divmmc_wp );
}

static void
widget_plusd_click( void )
{
  widget_options_settings.plusd = ! widget_options_settings.plusd;
}

static void
widget_option_plusd_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->plusd );
}

static void
widget_didaktik80_click( void )
{
  widget_options_settings.didaktik80 = ! widget_options_settings.didaktik80;
}

static void
widget_option_didaktik80_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->didaktik80 );
}

static void
widget_disciple_click( void )
{
  widget_options_settings.disciple = ! widget_options_settings.disciple;
}

static void
widget_option_disciple_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->disciple );
}

static void
widget_beta128_click( void )
{
  widget_options_settings.beta128 = ! widget_options_settings.beta128;
}

static void
widget_option_beta128_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->beta128 );
}

static void
widget_beta128_48boot_click( void )
{
  widget_options_settings.beta128_48boot = ! widget_options_settings.beta128_48boot;
}

static void
widget_option_beta128_48boot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->beta128_48boot );
}

static void
widget_opus_click( void )
{
  widget_options_settings.opus = ! widget_options_settings.opus;
}

static void
widget_option_opus_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->opus );
}

static void
widget_zxmmc_enabled_click( void )
{
  widget_options_settings.zxmmc_enabled = ! widget_options_settings.zxmmc_enabled;
}

static void
widget_option_zxmmc_enabled_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->zxmmc_enabled );
}

void
widget_peripherals_disk_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_peripherals_disk);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 17 );
    widget_peripherals_disk_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_peripherals_disk_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 17 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 17 ) {
      new_highlight_line = 17 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_peripherals_disk[highlight_line+1].click();
    options_peripherals_disk[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_disk + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_peripherals_disk_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_peripherals_disk[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_disk + old_highlight_line + 1, &widget_options_settings );
    options_peripherals_disk[highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_disk + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_peripherals_disk[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_peripherals_disk[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_peripherals_disk + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_rzx_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_rzx_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_rzx_running = 1;
  }

  error = widget_options_show_all( options_rzx, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_rzx_autosaves_click( void )
{
  widget_options_settings.rzx_autosaves = ! widget_options_settings.rzx_autosaves;
}

static void
widget_option_rzx_autosaves_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->rzx_autosaves );
}

static void
widget_rzx_compression_click( void )
{
  widget_options_settings.rzx_compression = ! widget_options_settings.rzx_compression;
}

static void
widget_option_rzx_compression_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->rzx_compression );
}

static void
widget_competition_mode_click( void )
{
  widget_options_settings.competition_mode = ! widget_options_settings.competition_mode;
}

static void
widget_option_competition_mode_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->competition_mode );
}

static void
widget_competition_code_click( void )
{
  widget_text_t text_data;

  text_data.title = "Competition code";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 8;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.competition_code );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.competition_code = atoi( widget_text_text );
  }
}

static void
widget_option_competition_code_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->competition_code,
                              menu->suffix );
}

static void
widget_embed_snapshot_click( void )
{
  widget_options_settings.embed_snapshot = ! widget_options_settings.embed_snapshot;
}

static void
widget_option_embed_snapshot_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->embed_snapshot );
}

void
widget_rzx_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_rzx);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 5 );
    widget_rzx_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_rzx_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 5 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 5 ) {
      new_highlight_line = 5 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_rzx[highlight_line+1].click();
    options_rzx[highlight_line+1].draw( menu_left_edge_x, menu_width, options_rzx + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_rzx_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_rzx[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_rzx + old_highlight_line + 1, &widget_options_settings );
    options_rzx[highlight_line+1].draw( menu_left_edge_x, menu_width, options_rzx + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_rzx[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_rzx[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_rzx + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_sound_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_sound_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_sound_running = 1;
  }

  error = widget_options_show_all( options_sound, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_sound_click( void )
{
  widget_options_settings.sound = ! widget_options_settings.sound;
}

static void
widget_option_sound_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->sound );
}

static void
widget_sound_load_click( void )
{
  widget_options_settings.sound_load = ! widget_options_settings.sound_load;
}

static void
widget_option_sound_load_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->sound_load );
}

static void
widget_stereo_ay_click( void )
{
  widget_combo_click( "AY stereo separation", widget_stereo_ay_combo,
				&widget_options_settings.stereo_ay,
				0 );
}

static void
widget_option_stereo_ay_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->stereo_ay, 0 );
}

static void
widget_sound_force_8bit_click( void )
{
  widget_options_settings.sound_force_8bit = ! widget_options_settings.sound_force_8bit;
}

static void
widget_option_sound_force_8bit_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->sound_force_8bit );
}

static void
widget_speaker_type_click( void )
{
  widget_combo_click( "Speaker type", widget_speaker_type_combo,
				&widget_options_settings.speaker_type,
				0 );
}

static void
widget_option_speaker_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->speaker_type, 0 );
}

static void
widget_volume_ay_click( void )
{
  widget_text_t text_data;

  text_data.title = "AY volume";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.volume_ay );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.volume_ay = atoi( widget_text_text );
  }
}

static void
widget_option_volume_ay_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->volume_ay,
                              menu->suffix );
}

static void
widget_volume_beeper_click( void )
{
  widget_text_t text_data;

  text_data.title = "Beeper volume";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.volume_beeper );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.volume_beeper = atoi( widget_text_text );
  }
}

static void
widget_option_volume_beeper_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->volume_beeper,
                              menu->suffix );
}

static void
widget_volume_specdrum_click( void )
{
  widget_text_t text_data;

  text_data.title = "SpecDrum volume";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.volume_specdrum );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.volume_specdrum = atoi( widget_text_text );
  }
}

static void
widget_option_volume_specdrum_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->volume_specdrum,
                              menu->suffix );
}

static void
widget_volume_covox_click( void )
{
  widget_text_t text_data;

  text_data.title = "Covox volume";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.volume_covox );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.volume_covox = atoi( widget_text_text );
  }
}

static void
widget_option_volume_covox_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->volume_covox,
                              menu->suffix );
}

static void
widget_volume_uspeech_click( void )
{
  widget_text_t text_data;

  text_data.title = "uSpeech volume";
  text_data.allow = WIDGET_INPUT_DIGIT;
  text_data.max_length = 3;
  snprintf( text_data.text, 40, "%d",
            widget_options_settings.volume_uspeech );
  widget_do_text( &text_data );

  if( widget_text_text ) {
    widget_options_settings.volume_uspeech = atoi( widget_text_text );
  }
}

static void
widget_option_volume_uspeech_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_entry( left_edge, width, menu->index, menu->text, show->volume_uspeech,
                              menu->suffix );
}

void
widget_sound_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_sound);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 10 );
    widget_sound_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_sound_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 10 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 10 ) {
      new_highlight_line = 10 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_sound[highlight_line+1].click();
    options_sound[highlight_line+1].draw( menu_left_edge_x, menu_width, options_sound + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_sound_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_sound[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_sound + old_highlight_line + 1, &widget_options_settings );
    options_sound[highlight_line+1].draw( menu_left_edge_x, menu_width, options_sound + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_sound[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_sound[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_sound + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_diskoptions_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_diskoptions_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_diskoptions_running = 1;
  }

  error = widget_options_show_all( options_diskoptions, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_drive_plus3a_type_click( void )
{
  widget_combo_click( "+3 Drive A", widget_drive_plus3a_type_combo,
				&widget_options_settings.drive_plus3a_type,
				0 );
}

static void
widget_option_drive_plus3a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_plus3a_type, 0 );
}

static void
widget_drive_plus3b_type_click( void )
{
  widget_combo_click( "+3 Drive B", widget_drive_plus3b_type_combo,
				&widget_options_settings.drive_plus3b_type,
				4 );
}

static void
widget_option_drive_plus3b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_plus3b_type, 4 );
}

static void
widget_plus3_detect_speedlock_click( void )
{
  widget_options_settings.plus3_detect_speedlock = ! widget_options_settings.plus3_detect_speedlock;
}

static void
widget_option_plus3_detect_speedlock_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->plus3_detect_speedlock );
}

static void
widget_drive_beta128a_type_click( void )
{
  widget_combo_click( "Beta 128 Drive A", widget_drive_beta128a_type_combo,
				&widget_options_settings.drive_beta128a_type,
				3 );
}

static void
widget_option_drive_beta128a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_beta128a_type, 3 );
}

static void
widget_drive_beta128b_type_click( void )
{
  widget_combo_click( "Beta 128 Drive B", widget_drive_beta128b_type_combo,
				&widget_options_settings.drive_beta128b_type,
				4 );
}

static void
widget_option_drive_beta128b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_beta128b_type, 4 );
}

static void
widget_drive_beta128c_type_click( void )
{
  widget_combo_click( "Beta 128 Drive C", widget_drive_beta128c_type_combo,
				&widget_options_settings.drive_beta128c_type,
				4 );
}

static void
widget_option_drive_beta128c_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_beta128c_type, 4 );
}

static void
widget_drive_beta128d_type_click( void )
{
  widget_combo_click( "Beta 128 Drive D", widget_drive_beta128d_type_combo,
				&widget_options_settings.drive_beta128d_type,
				4 );
}

static void
widget_option_drive_beta128d_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_beta128d_type, 4 );
}

static void
widget_drive_plusd1_type_click( void )
{
  widget_combo_click( "+D Drive 1", widget_drive_plusd1_type_combo,
				&widget_options_settings.drive_plusd1_type,
				3 );
}

static void
widget_option_drive_plusd1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_plusd1_type, 3 );
}

static void
widget_drive_plusd2_type_click( void )
{
  widget_combo_click( "+D Drive 2", widget_drive_plusd2_type_combo,
				&widget_options_settings.drive_plusd2_type,
				4 );
}

static void
widget_option_drive_plusd2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_plusd2_type, 4 );
}

static void
widget_drive_didaktik80a_type_click( void )
{
  widget_combo_click( "Didaktik 80 Drive A", widget_drive_didaktik80a_type_combo,
				&widget_options_settings.drive_didaktik80a_type,
				3 );
}

static void
widget_option_drive_didaktik80a_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_didaktik80a_type, 3 );
}

static void
widget_drive_didaktik80b_type_click( void )
{
  widget_combo_click( "Didaktik 80 Drive B", widget_drive_didaktik80b_type_combo,
				&widget_options_settings.drive_didaktik80b_type,
				4 );
}

static void
widget_option_drive_didaktik80b_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_didaktik80b_type, 4 );
}

static void
widget_drive_disciple1_type_click( void )
{
  widget_combo_click( "DISCiPLE Drive 1", widget_drive_disciple1_type_combo,
				&widget_options_settings.drive_disciple1_type,
				3 );
}

static void
widget_option_drive_disciple1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_disciple1_type, 3 );
}

static void
widget_drive_disciple2_type_click( void )
{
  widget_combo_click( "DISCiPLE Drive 2", widget_drive_disciple2_type_combo,
				&widget_options_settings.drive_disciple2_type,
				4 );
}

static void
widget_option_drive_disciple2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_disciple2_type, 4 );
}

static void
widget_drive_opus1_type_click( void )
{
  widget_combo_click( "Opus Drive 1", widget_drive_opus1_type_combo,
				&widget_options_settings.drive_opus1_type,
				0 );
}

static void
widget_option_drive_opus1_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_opus1_type, 0 );
}

static void
widget_drive_opus2_type_click( void )
{
  widget_combo_click( "Opus Drive 2", widget_drive_opus2_type_combo,
				&widget_options_settings.drive_opus2_type,
				1 );
}

static void
widget_option_drive_opus2_type_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->drive_opus2_type, 1 );
}

static void
widget_disk_try_merge_click( void )
{
  widget_combo_click( "Try merge 'B' side of disks", widget_disk_try_merge_combo,
				&widget_options_settings.disk_try_merge,
				1 );
}

static void
widget_option_disk_try_merge_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->disk_try_merge, 1 );
}

static void
widget_disk_ask_merge_click( void )
{
  widget_options_settings.disk_ask_merge = ! widget_options_settings.disk_ask_merge;
}

static void
widget_option_disk_ask_merge_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->disk_ask_merge );
}

void
widget_diskoptions_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_diskoptions);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 17 );
    widget_diskoptions_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_diskoptions_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 17 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 17 ) {
      new_highlight_line = 17 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_diskoptions[highlight_line+1].click();
    options_diskoptions[highlight_line+1].draw( menu_left_edge_x, menu_width, options_diskoptions + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_diskoptions_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_diskoptions[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_diskoptions + old_highlight_line + 1, &widget_options_settings );
    options_diskoptions[highlight_line+1].draw( menu_left_edge_x, menu_width, options_diskoptions + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_diskoptions[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_diskoptions[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_diskoptions + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

int
widget_movie_draw( void *data GCC_UNUSED )
{
  int error;

  if( !widget_movie_running ) {		/* we want to copy settings, only when start up */
    highlight_line = 0;
    /* Get a copy of the current settings */
    settings_copy( &widget_options_settings, &settings_current );
    widget_movie_running = 1;
  }

  error = widget_options_show_all( options_movie, &widget_options_settings );
  if( error ) { settings_free( &widget_options_settings ); return error; }

  return 0;
}

static void
widget_movie_compr_click( void )
{
  widget_combo_click( "Movie compression", widget_movie_compr_combo,
				&widget_options_settings.movie_compr,
				1 );
}

static void
widget_option_movie_compr_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_combo( left_edge, width, menu->index, menu->text, menu->options,
			      show->movie_compr, 1 );
}

static void
widget_movie_stop_after_rzx_click( void )
{
  widget_options_settings.movie_stop_after_rzx = ! widget_options_settings.movie_stop_after_rzx;
}

static void
widget_option_movie_stop_after_rzx_draw( int left_edge, int width, struct widget_option_entry *menu, settings_info *show )
{
  widget_options_print_option( left_edge, width, menu->index, menu->text, show->movie_stop_after_rzx );
}

void
widget_movie_keyhandler( input_key key )
{
  int new_highlight_line = 0;
  int cursor_pressed = 0;
  widget_option_entry *ptr;
  int menu_width = widget_calculate_option_width(options_movie);
  int menu_left_edge_x = DISPLAY_WIDTH_COLS/2-menu_width/2;

  switch( key ) {

#if 0
  case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
    widget_dialog_with_border( 1, 2, 30, 2 + 2 );
    widget_movie_show_all( &widget_options_settings );
    break;
#endif
    
  case INPUT_KEY_Escape:
  case INPUT_JOYSTICK_FIRE_2:
    widget_end_widget( WIDGET_FINISHED_CANCEL );
    widget_movie_running = 0;
    break;

  case INPUT_KEY_Up:
  case INPUT_KEY_7:
  case INPUT_JOYSTICK_UP:
    if ( highlight_line ) {
      new_highlight_line = highlight_line - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Down:
  case INPUT_KEY_6:
  case INPUT_JOYSTICK_DOWN:
    if ( highlight_line + 1 < 2 ) {
      new_highlight_line = highlight_line + 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_Home:
    if ( highlight_line ) {
      new_highlight_line = 0;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_End:
    if ( highlight_line + 2 < 2 ) {
      new_highlight_line = 2 - 1;
      cursor_pressed = 1;
    }
    break;

  case INPUT_KEY_space:
  case INPUT_KEY_0:
  case INPUT_JOYSTICK_RIGHT:
    options_movie[highlight_line+1].click();
    options_movie[highlight_line+1].draw( menu_left_edge_x, menu_width, options_movie + highlight_line + 1, &widget_options_settings );
    return;

  case INPUT_KEY_Return:
  case INPUT_KEY_KP_Enter:
  case INPUT_JOYSTICK_FIRE_1:
    widget_end_all( WIDGET_FINISHED_OK );
    widget_movie_running = 0;
    display_refresh_all();
    return;

  default:	/* Keep gcc happy */
    break;

  }

  if( cursor_pressed ) {
    int old_highlight_line = highlight_line;
    highlight_line = new_highlight_line;
    options_movie[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_movie + old_highlight_line + 1, &widget_options_settings );
    options_movie[highlight_line+1].draw( menu_left_edge_x, menu_width, options_movie + highlight_line + 1, &widget_options_settings );
    return;
  }

  for( ptr=&options_movie[1]; ptr->text != NULL; ptr++ ) {
    if( key == ptr->key ) {
      int old_highlight_line = highlight_line;
      ptr->click();
      highlight_line = ptr->index;
      options_movie[old_highlight_line+1].draw( menu_left_edge_x, menu_width, options_movie + old_highlight_line + 1, &widget_options_settings );
      ptr->draw( menu_left_edge_x, menu_width, ptr, &widget_options_settings );
      break;
    }
  }
}

#endif				/* #ifdef USE_WIDGET */
