1
0
mirror of https://git.code.sf.net/p/fuse-emulator/fuse synced 2026-01-27 01:41:34 +03:00
Files
fuse/ui/widget/binary.c
2021-03-16 20:05:26 +11:00

459 lines
10 KiB
C

/* binary.c: The binary load/save widgets
Copyright (c) 2019 Gergely Szasz
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: szaszg@hu.inter.net
*/
#include "config.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "fuse.h"
#include "utils.h"
#include "widget_internals.h"
typedef struct {
int confirm;
ui_confirm_save_t save;
const char *title;
char *filename;
utils_file file;
int load;
char *start_str;
char *length_str;
libspectrum_dword start;
libspectrum_dword length;
} widget_binary_t;
static widget_binary_t widget_binary;
struct widget_binary_entry;
/* A generic click function */
typedef void (*widget_binary_click_fn)( void );
/* A general menu */
typedef struct widget_binary_entry {
const char *text;
int x, y;
widget_binary_click_fn click;
} widget_binary_entry;
static void widget_browse_click( void );
static void widget_start_click( void );
static void widget_length_click( void );
static void widget_cancel_click( void );
static void widget_ok_click( void );
static widget_binary_entry binary_entry[] = {
{ "\012B\001rowse", 208, 28, widget_browse_click },
{ "\012S\001tart", 16, 40, widget_start_click },
{ "\012L\001ength", 16, 48, widget_length_click },
{ "\012C\001ancel", 186, 68, widget_cancel_click },
{ "\012O\001k", 228, 68, widget_ok_click },
{ NULL }
};
static size_t highlight_entry = 0;
static void
widget_binary_entry_draw( int index, int highlight )
{
int w = widget_stringwidth( binary_entry[index].text );
widget_rectangle( binary_entry[index].x - 1, binary_entry[index].y, w + 2, 8,
highlight ? WIDGET_COLOUR_HIGHLIGHT : WIDGET_COLOUR_BACKGROUND );
widget_printstring( binary_entry[index].x, binary_entry[index].y,
WIDGET_COLOUR_FOREGROUND, binary_entry[index].text );
widget_display_rasters( binary_entry[index].y, 8 );
}
static void
display_filename( void )
{
const char *fn;
fn = widget_binary.filename;
while( widget_stringwidth( fn ) >= 136 ) fn++;
widget_rectangle( 68, 28, 136, 8, WIDGET_COLOUR_BACKGROUND );
widget_printstring( 68, 28, WIDGET_COLOUR_DISABLED, fn );
widget_display_lines( 3, 2 );
}
static void
display_start( void )
{
widget_rectangle( 68, 40, 136, 8, WIDGET_COLOUR_BACKGROUND );
widget_printstring( 68, 40, WIDGET_COLOUR_FOREGROUND,
widget_binary.start_str );
widget_display_lines( 5, 1 );
}
static void
display_length( void )
{
widget_rectangle( 68, 48, 136, 8, WIDGET_COLOUR_BACKGROUND );
widget_printstring( 68, 48, WIDGET_COLOUR_FOREGROUND,
widget_binary.length_str );
widget_display_lines( 6, 1 );
}
static void
display_all( void )
{
display_filename();
display_start();
display_length();
}
int
widget_binary_draw( void *data )
{
int i;
widget_dialog_with_border( 1, 2, 30, 8 );
widget_printstring( 10, 16, WIDGET_COLOUR_TITLE, widget_binary.title );
widget_printstring( 16, 28, WIDGET_COLOUR_FOREGROUND, "Filename: " );
display_all();
for( i = 0; binary_entry[i].text != NULL; i++ ) {
widget_binary_entry_draw( i, ( highlight_entry == i ) );
}
widget_display_lines( 2, 8 );
return 0;
}
static void
ask_filename( void )
{
widget_filesel_data filesel;
filesel.exit_all_widgets = 0;
if( widget_binary.load ) {
filesel.title = "Fuse - Load Binary Data";
widget_do_fileselector( &filesel );
} else {
filesel.title = "Fuse - Save Binary Data";
widget_do_fileselector_save( &filesel );
}
if( !widget_filesel_name ) return;
free( widget_binary.filename );
widget_binary.filename = utils_safe_strdup( widget_filesel_name );
display_filename();
}
static void
ask_start( void )
{
long int value;
char *s = widget_binary.start_str;
widget_text_t text_data;
text_data.allow = WIDGET_INPUT_ALNUM;
text_data.max_length = 9;
text_data.title = "Enter start value";
snprintf( text_data.text, sizeof( text_data.text ), "%s", s );
widget_do_text( &text_data );
if( !widget_text_text ) return;
value = strtol( widget_text_text, &s, 0 );
if( *s != '\0' ) {
ui_error( UI_ERROR_ERROR, "Invalid number" );
return;
}
if( value < 0 || value > 0xffff ) {
ui_error( UI_ERROR_ERROR, "Start must be between 0 and 65535" );
} else if( value + widget_binary.length > 0x10000 ) {
ui_error( UI_ERROR_ERROR, "Block ends after address 65535" );
} else {
free( widget_binary.start_str );
widget_binary.start_str = utils_safe_strdup( widget_text_text );
widget_binary.start = value;
}
display_start();
}
static void
ask_length( void )
{
long int value;
char *s = widget_binary.length_str;
widget_text_t text_data;
text_data.allow = WIDGET_INPUT_ALNUM;
text_data.max_length = 9;
text_data.title = "Enter length";
snprintf( text_data.text, sizeof( text_data.text ), "%s", s );
widget_do_text( &text_data );
if( !widget_text_text ) return;
value = strtol( widget_text_text, &s, 0 );
if( *s != '\0' ) {
ui_error( UI_ERROR_ERROR, "Invalid number" );
return;
}
if( value < 1 || value > 0x10000 ) {
ui_error( UI_ERROR_ERROR, "Length must be between 1 and 65536" );
} else if( value + widget_binary.start > 0x10000 ) {
ui_error( UI_ERROR_ERROR, "Block ends after address 65535" );
} else if( widget_binary.load && value > widget_binary.file.length ) {
ui_error( UI_ERROR_ERROR, "'%s' contains only %lu bytes",
widget_binary.filename, (unsigned long)widget_binary.file.length
);
return;
} else {
free( widget_binary.length_str );
widget_binary.length_str = utils_safe_strdup( widget_text_text );
widget_binary.length = value;
}
display_length();
}
static void
load_data( void )
{
libspectrum_dword i;
for( i = 0; i < widget_binary.length; i++ )
writebyte_internal( widget_binary.start + i,
widget_binary.file.buffer[ i ] );
}
static void
save_data( void )
{
int error;
error = utils_save_binary( widget_binary.start, widget_binary.length,
widget_binary.filename );
/* TODO: some error reporting */
if( error ) return;
}
static void
widget_browse_click( void )
{
ask_filename();
}
static void
widget_start_click( void )
{
ask_start();
}
static void
widget_length_click( void )
{
ask_length();
}
static void
widget_cancel_click( void )
{
widget_end_widget( WIDGET_FINISHED_CANCEL );
}
static void
widget_ok_click( void )
{
if( widget_binary.load ) {
load_data();
} else {
save_data();
}
widget_end_all( WIDGET_FINISHED_OK );
display_refresh_all();
}
void
widget_binary_keyhandler( input_key key )
{
int new_highlight_entry = highlight_entry;
int clicked = 0;
switch( key ) {
#if 0
case INPUT_KEY_Resize: /* Fake keypress used on window resize */
widget_dialog_with_border( 1, 2, 30, 2 + 20 );
widget_general_show_all( &widget_options_settings );
break;
#endif
case INPUT_KEY_c:
case INPUT_KEY_C:
case INPUT_KEY_Escape:
case INPUT_KEY_F10:
case INPUT_JOYSTICK_FIRE_2:
new_highlight_entry = 3;
clicked = 1;
break;
case INPUT_KEY_b:
case INPUT_KEY_B:
new_highlight_entry = 0;
clicked = 1;
break;
case INPUT_KEY_s:
case INPUT_KEY_S:
new_highlight_entry = 1;
clicked = 1;
break;
case INPUT_KEY_l:
case INPUT_KEY_L:
new_highlight_entry = 2;
clicked = 1;
break;
case INPUT_KEY_o:
case INPUT_KEY_O:
new_highlight_entry = 4;
clicked = 1;
break;
case INPUT_KEY_Up:
case INPUT_KEY_7:
case INPUT_JOYSTICK_UP:
new_highlight_entry = highlight_entry - 1;
if( new_highlight_entry < 0 )
while( binary_entry[new_highlight_entry + 1].text != NULL )
new_highlight_entry++;
break;
case INPUT_KEY_Down:
case INPUT_KEY_6:
case INPUT_JOYSTICK_DOWN:
new_highlight_entry = highlight_entry + 1;
if( binary_entry[new_highlight_entry].text == NULL )
new_highlight_entry = 0;
break;
case INPUT_KEY_Return:
case INPUT_KEY_KP_Enter:
case INPUT_JOYSTICK_FIRE_1:
clicked = 1;
default: /* Keep gcc happy */
break;
}
if( highlight_entry != new_highlight_entry ) {
widget_binary_entry_draw( highlight_entry, 0 );
widget_binary_entry_draw( new_highlight_entry, 1 );
highlight_entry = new_highlight_entry;
}
if( clicked ) binary_entry[highlight_entry].click();
}
int
widget_binary_finish( widget_finish_state finished )
{
free( widget_binary.start_str );
free( widget_binary.length_str );
free( widget_binary.filename );
return 0;
}
static void
init_widget_binary( void )
{
char str[8];
highlight_entry = 0;
widget_binary.start = 0;
widget_binary.length = widget_binary.load &&
widget_binary.file.length < 65536 ? widget_binary.file.length : 65536;
snprintf( str, 8, "%d", widget_binary.length );
widget_binary.start_str = utils_safe_strdup( "0" );
widget_binary.length_str = utils_safe_strdup( str );
}
int
menu_file_loadbinarydata( int action )
{
int error;
fuse_emulation_pause();
widget_binary.filename = ui_get_open_filename( "Fuse - Load Binary Data" );
if( !widget_binary.filename ) {
fuse_emulation_unpause();
return 1;
}
error = utils_read_file( widget_binary.filename, &widget_binary.file );
if( error ) {
free( widget_binary.filename );
fuse_emulation_unpause();
return 1;
}
widget_binary.load = 1;
widget_binary.title = "Fuse - Load Binary Data";
init_widget_binary();
/* Run dialog */
widget_do_binary();
utils_close_file( &widget_binary.file );
fuse_emulation_unpause();
return 0;
}
int
menu_file_savebinarydata( int action )
{
fuse_emulation_pause();
widget_binary.filename = ui_get_save_filename( "Fuse - Save Binary Data" );
if( !widget_binary.filename ) {
fuse_emulation_unpause();
return 1;
}
widget_binary.load = 0;
widget_binary.title = "Fuse - Save Binary Data";
init_widget_binary();
/* Run dialog */
widget_do_binary();
fuse_emulation_unpause();
return 0;
}