mirror of
https://git.code.sf.net/p/fuse-emulator/fuse
synced 2026-01-27 01:41:34 +03:00
1011 lines
26 KiB
C
1011 lines
26 KiB
C
/* filesel.c: File selection dialog box
|
|
Copyright (c) 2001-2015 Matan Ziv-Av, Philip Kendall, Russell Marks,
|
|
Marek Januszewski
|
|
Copyright (c) 2015 Sergio Baldoví
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_STRINGS_STRCASECMP
|
|
#include <strings.h>
|
|
#endif /* #ifdef HAVE_STRINGS_STRCASECMP */
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#include <ctype.h>
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
#include "fuse.h"
|
|
#include "ui/ui.h"
|
|
#include "utils.h"
|
|
#include "widget_internals.h"
|
|
|
|
#if defined AMIGA || defined __MORPHOS__
|
|
#include <proto/asl.h>
|
|
#include <proto/dos.h>
|
|
#include <proto/exec.h>
|
|
|
|
struct Library *AslBase;
|
|
|
|
#ifndef __MORPHOS__
|
|
struct AslIFace *IAsl;
|
|
struct Library *DOSBase;
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
|
|
#ifndef __MORPHOS__
|
|
struct DOSIFace *IDOS;
|
|
struct Library *ExecBase;
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
|
|
|
|
int err = 0;
|
|
|
|
char *amiga_asl( char *title, BOOL is_saving );
|
|
|
|
#endif /* ifdef AMIGA */
|
|
|
|
struct widget_dirent **widget_filenames; /* Filenames in the current
|
|
directory */
|
|
size_t widget_numfiles; /* The number of files in the current
|
|
directory */
|
|
|
|
static const char *title;
|
|
static int is_saving;
|
|
|
|
#ifdef WIN32
|
|
static int is_drivesel = 0;
|
|
static int is_rootdir;
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
#define ENTRIES_PER_SCREEN (is_saving ? 32 : 36)
|
|
|
|
/* The number of the filename in the top-left corner of the current
|
|
display, that of the filename which the `cursor' is on, and that
|
|
which it will be on after this keypress */
|
|
static size_t top_left_file, current_file, new_current_file;
|
|
|
|
static char *widget_get_filename( const char *title, int saving );
|
|
|
|
static int widget_add_filename( int *allocated, int *number,
|
|
struct widget_dirent ***namelist,
|
|
const char *name );
|
|
static void widget_scan( char *dir );
|
|
static int widget_select_file( const char *name );
|
|
static int widget_scan_compare( const widget_dirent **a,
|
|
const widget_dirent **b );
|
|
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
static char* widget_getcwd( void );
|
|
#endif /* ifndef AMIGA */
|
|
static int widget_print_all_filenames( struct widget_dirent **filenames, int n,
|
|
int top_left, int current,
|
|
const char *dir );
|
|
static int widget_print_filename( struct widget_dirent *filename, int position,
|
|
int inverted );
|
|
#ifdef WIN32
|
|
static void widget_filesel_chdrv( void );
|
|
static void widget_filesel_drvlist( void );
|
|
#endif /* #ifdef WIN32 */
|
|
static int widget_filesel_chdir( void );
|
|
|
|
/* The filename to return */
|
|
char* widget_filesel_name;
|
|
|
|
/* Should we exit all widgets when we're done with this selector? */
|
|
static int exit_all_widgets;
|
|
|
|
static char *
|
|
widget_get_filename( const char *title, int saving )
|
|
{
|
|
char *filename = NULL;
|
|
|
|
widget_filesel_data data;
|
|
|
|
data.exit_all_widgets = 1;
|
|
data.title = title;
|
|
|
|
if( saving ) {
|
|
widget_do_fileselector_save( &data );
|
|
} else {
|
|
widget_do_fileselector( &data );
|
|
}
|
|
if( widget_filesel_name )
|
|
filename = utils_safe_strdup( widget_filesel_name );
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
char *
|
|
ui_get_open_filename( const char *title )
|
|
{
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
return widget_get_filename( title, 0 );
|
|
#else
|
|
return amiga_asl( title, FALSE );
|
|
#endif
|
|
}
|
|
|
|
char *
|
|
ui_get_save_filename( const char *title )
|
|
{
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
return widget_get_filename( title, 1 );
|
|
#else
|
|
return amiga_asl( title, TRUE );
|
|
#endif
|
|
}
|
|
|
|
static int widget_add_filename( int *allocated, int *number,
|
|
struct widget_dirent ***namelist,
|
|
const char *name ) {
|
|
int i; size_t length;
|
|
|
|
if( ++*number > *allocated ) {
|
|
struct widget_dirent **oldptr = *namelist;
|
|
|
|
*namelist = realloc( (*namelist), 2 * *allocated * sizeof(**namelist) );
|
|
if( *namelist == NULL ) {
|
|
for( i=0; i<*number-1; i++ ) {
|
|
free( oldptr[i]->name );
|
|
free( oldptr[i] );
|
|
}
|
|
free( oldptr );
|
|
return -1;
|
|
}
|
|
*allocated *= 2;
|
|
}
|
|
|
|
(*namelist)[*number-1] = malloc( sizeof(***namelist) );
|
|
if( !(*namelist)[*number-1] ) {
|
|
for( i=0; i<*number-1; i++ ) {
|
|
free( (*namelist)[i]->name );
|
|
free( (*namelist)[i] );
|
|
}
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
return -1;
|
|
}
|
|
|
|
length = strlen( name ) + 1;
|
|
if( length < 16 ) length = 16;
|
|
|
|
(*namelist)[*number-1]->name = malloc( length );
|
|
if( !(*namelist)[*number-1]->name ) {
|
|
free( (*namelist)[*number-1] );
|
|
for( i=0; i<*number-1; i++ ) {
|
|
free( (*namelist)[i]->name );
|
|
free( (*namelist)[i] );
|
|
}
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
return -1;
|
|
}
|
|
|
|
strncpy( (*namelist)[*number-1]->name, name, length );
|
|
(*namelist)[*number-1]->name[ length - 1 ] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined AMIGA || defined __MORPHOS__
|
|
char *
|
|
amiga_asl( char *title, BOOL is_saving ) {
|
|
char *filename;
|
|
struct FileRequester *filereq;
|
|
|
|
#ifndef __MORPHOS__
|
|
if( AslBase = IExec->OpenLibrary( "asl.library", 52 ) ) {
|
|
if( IAsl = ( struct AslIFace * ) IExec->GetInterface( AslBase,"main",1,NULL ) ) {
|
|
filereq = IAsl->AllocAslRequestTags( ASL_FileRequest,
|
|
ASLFR_RejectIcons,TRUE,
|
|
ASLFR_TitleText,title,
|
|
ASLFR_DoSaveMode,is_saving,
|
|
ASLFR_InitialPattern,"#?.(sna|z80|szx|sp|snp|zxs|tap|tzx|csw|rzx|dsk|trd|scl|mdr|dck|hdf|rom|psg|scr|mlt|png|gz|bz2)",
|
|
ASLFR_DoPatterns,TRUE,
|
|
TAG_DONE );
|
|
if( err = IAsl->AslRequest( filereq, NULL ) ) {
|
|
filename = ( STRPTR ) IExec->AllocVec( 1024, MEMF_CLEAR );
|
|
#else /* #ifndef __MORPHOS__ */
|
|
if( AslBase = OpenLibrary( "asl.library", 0 ) ) {
|
|
filereq = AllocAslRequestTags( ASL_FileRequest,
|
|
ASLFR_RejectIcons,TRUE,
|
|
ASLFR_TitleText,title,
|
|
ASLFR_DoSaveMode,is_saving,
|
|
ASLFR_InitialPattern,"#?.(sna|z80|szx|sp|snp|zxs|tap|tzx|csw|rzx|dsk|trd|scl|mdr|dck|hdf|rom|psg|scr|mlt|png|gz|bz2)",
|
|
ASLFR_DoPatterns,TRUE,
|
|
TAG_DONE );
|
|
if( err = AslRequest( filereq, NULL ) ) {
|
|
filename = ( STRPTR ) AllocVec( 1024, MEMF_CLEAR );
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
|
|
strcpy( filename,filereq->fr_Drawer );
|
|
#ifndef __MORPHOS__
|
|
IDOS->AddPart( filename, filereq->fr_File, 1024 );
|
|
#else /* #ifndef __MORPHOS__ */
|
|
AddPart( filename, filereq->fr_File, 1024 );
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
widget_filesel_name = utils_safe_strdup( filename );
|
|
#ifndef __MORPHOS__
|
|
IExec->FreeVec( filename );
|
|
#else /* #ifndef __MORPHOS__ */
|
|
FreeVec( filename );
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
err = WIDGET_FINISHED_OK;
|
|
} else {
|
|
err = WIDGET_FINISHED_CANCEL;
|
|
}
|
|
#ifndef __MORPHOS__
|
|
IExec->DropInterface( ( struct Interface * )IAsl );
|
|
}
|
|
IExec->CloseLibrary( AslBase );
|
|
#else /* #ifndef __MORPHOS__ */
|
|
CloseLibrary( AslBase );
|
|
#endif /* #ifndef __MORPHOS__ */
|
|
}
|
|
return widget_filesel_name;
|
|
}
|
|
#else /* ifdef AMIGA */
|
|
|
|
static int widget_scandir( const char *dir, struct widget_dirent ***namelist,
|
|
int (*select_fn)(const char*) )
|
|
{
|
|
compat_dir directory;
|
|
|
|
int allocated, number;
|
|
int i;
|
|
int done = 0;
|
|
|
|
*namelist = malloc( 32 * sizeof(**namelist) );
|
|
if( !*namelist ) return -1;
|
|
|
|
allocated = 32; number = 0;
|
|
|
|
directory = compat_opendir( dir );
|
|
if( !directory ) {
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
return -1;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
/* Assume this is the root directory, unless we find an entry named ".." */
|
|
is_rootdir = 1;
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
while( !done ) {
|
|
char name[ PATH_MAX ];
|
|
|
|
compat_dir_result_t result =
|
|
compat_readdir( directory, name, sizeof( name ) );
|
|
|
|
switch( result )
|
|
{
|
|
case COMPAT_DIR_RESULT_OK:
|
|
if( select_fn( name ) ) {
|
|
#ifdef WIN32
|
|
if( is_rootdir && !strcmp( name, ".." ) ) {
|
|
is_rootdir = 0;
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
if( widget_add_filename( &allocated, &number, namelist, name ) ) {
|
|
compat_closedir( directory );
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COMPAT_DIR_RESULT_END:
|
|
done = 1;
|
|
break;
|
|
|
|
case COMPAT_DIR_RESULT_ERROR:
|
|
for( i=0; i<number; i++ ) {
|
|
free( (*namelist)[i]->name );
|
|
free( (*namelist)[i] );
|
|
}
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
compat_closedir( directory );
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
if( compat_closedir( directory ) ) {
|
|
for( i=0; i<number; i++ ) {
|
|
free( (*namelist)[i]->name );
|
|
free( (*namelist)[i] );
|
|
}
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
return -1;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
if( is_rootdir ) {
|
|
/* Add a fake ".." entry for drive selection */
|
|
if( widget_add_filename( &allocated, &number, namelist, ".." ) ) {
|
|
return -1;
|
|
}
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
return number;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
static int widget_scandrives( struct widget_dirent ***namelist )
|
|
{
|
|
int allocated, number;
|
|
unsigned long drivemask;
|
|
int i;
|
|
char drive[3];
|
|
const char *driveletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
drive[1] = ':';
|
|
drive[2] = '\0';
|
|
|
|
*namelist = malloc( 32 * sizeof(**namelist) );
|
|
if( !*namelist ) return -1;
|
|
|
|
allocated = 32; number = 0;
|
|
|
|
drivemask = _getdrives();
|
|
if( !drivemask ) {
|
|
free( *namelist );
|
|
*namelist = NULL;
|
|
return -1;
|
|
}
|
|
|
|
for( i = 0; i < 26; i++ ) {
|
|
if( drivemask & 1) {
|
|
drive[0] = driveletters[i];
|
|
if( widget_add_filename( &allocated, &number, namelist, drive ) ) {
|
|
return -1;
|
|
}
|
|
}
|
|
drivemask >>= 1;
|
|
}
|
|
|
|
return number;
|
|
}
|
|
#endif
|
|
|
|
static void widget_scan( char *dir )
|
|
{
|
|
struct stat file_info;
|
|
|
|
size_t i; int error;
|
|
|
|
/* Free the memory belonging to the files in the previous directory */
|
|
for( i=0; i<widget_numfiles; i++ ) {
|
|
free( widget_filenames[i]->name );
|
|
free( widget_filenames[i] );
|
|
}
|
|
|
|
#ifdef WIN32
|
|
if( dir ) {
|
|
widget_numfiles = widget_scandir( dir, &widget_filenames,
|
|
widget_select_file );
|
|
} else {
|
|
widget_numfiles = widget_scandrives( &widget_filenames );
|
|
}
|
|
#else /* #ifdef WIN32 */
|
|
widget_numfiles = widget_scandir( dir, &widget_filenames,
|
|
widget_select_file );
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
if( widget_numfiles == (size_t)-1 ) return;
|
|
|
|
for( i=0; i<widget_numfiles; i++ ) {
|
|
error = stat( widget_filenames[i]->name, &file_info );
|
|
widget_filenames[i]->mode = error ? 0 : file_info.st_mode;
|
|
}
|
|
|
|
qsort( widget_filenames, widget_numfiles, sizeof(struct widget_dirent*),
|
|
(int(*)(const void*,const void*))widget_scan_compare );
|
|
|
|
}
|
|
|
|
static int
|
|
widget_select_file( const char *name )
|
|
{
|
|
if( !name ) return 0;
|
|
|
|
/* Skip current directory */
|
|
if( !strcmp( name, "." ) ) return 0;
|
|
|
|
#ifndef WIN32
|
|
/* Skip hidden files/directories */
|
|
if( strlen( name ) > 1 && name[0] == '.' && name[1] != '.' ) return 0;
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int widget_scan_compare( const struct widget_dirent **a,
|
|
const struct widget_dirent **b )
|
|
{
|
|
int isdir1 = S_ISDIR( (*a)->mode ),
|
|
isdir2 = S_ISDIR( (*b)->mode );
|
|
|
|
if( isdir1 && !isdir2 ) {
|
|
return -1;
|
|
} else if( isdir2 && !isdir1 ) {
|
|
return 1;
|
|
} else {
|
|
return strcmp( (*a)->name, (*b)->name );
|
|
}
|
|
|
|
}
|
|
#endif /* ifdef AMIGA */
|
|
|
|
/* File selection widget */
|
|
|
|
static int
|
|
widget_filesel_draw( void *data )
|
|
{
|
|
widget_filesel_data *filesel_data = data;
|
|
char *directory;
|
|
int error;
|
|
|
|
exit_all_widgets = filesel_data->exit_all_widgets;
|
|
title = filesel_data->title;
|
|
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
#ifdef WIN32
|
|
if( !is_drivesel ) {
|
|
directory = widget_getcwd();
|
|
if( directory == NULL ) return 1;
|
|
} else {
|
|
directory = NULL;
|
|
}
|
|
#else /* #ifdef WIN32 */
|
|
directory = widget_getcwd();
|
|
if( directory == NULL ) return 1;
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
widget_scan( directory );
|
|
new_current_file = current_file = 0;
|
|
top_left_file = 0;
|
|
|
|
/* Create the dialog box */
|
|
error = widget_dialog_with_border( 1, 2, 30, 22 );
|
|
if( error ) {
|
|
free( directory );
|
|
return error;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
if( directory == NULL ) {
|
|
directory = utils_safe_strdup( "Drive selection" );
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
/* Show all the filenames */
|
|
widget_print_all_filenames( widget_filenames, widget_numfiles,
|
|
top_left_file, current_file, directory );
|
|
|
|
free( directory );
|
|
|
|
#endif /* ifndef AMIGA */
|
|
|
|
return 0;
|
|
}
|
|
|
|
int widget_filesel_finish( widget_finish_state finished ) {
|
|
|
|
/* Return with null if we didn't finish cleanly */
|
|
if( finished != WIDGET_FINISHED_OK ) {
|
|
if( widget_filesel_name ) free( widget_filesel_name );
|
|
widget_filesel_name = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
widget_filesel_load_draw( void *data )
|
|
{
|
|
is_saving = 0;
|
|
return widget_filesel_draw( data );
|
|
}
|
|
|
|
int
|
|
widget_filesel_save_draw( void *data )
|
|
{
|
|
is_saving = 1;
|
|
return widget_filesel_draw( data );
|
|
}
|
|
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
static char* widget_getcwd( void )
|
|
{
|
|
char *directory; size_t directory_length;
|
|
char *ptr;
|
|
|
|
directory_length = 64;
|
|
directory = malloc( directory_length * sizeof( char ) );
|
|
if( directory == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
do {
|
|
ptr = getcwd( directory, directory_length );
|
|
if( ptr ) break;
|
|
if( errno == ERANGE ) {
|
|
ptr = directory;
|
|
directory_length *= 2;
|
|
directory =
|
|
(char*)realloc( directory, directory_length * sizeof( char ) );
|
|
if( directory == NULL ) {
|
|
free( ptr );
|
|
return NULL;
|
|
}
|
|
} else {
|
|
free( directory );
|
|
return NULL;
|
|
}
|
|
} while(1);
|
|
|
|
#ifdef WIN32
|
|
if( directory[0] && directory[1] == ':' ) {
|
|
directory[0] = toupper( directory[0] );
|
|
}
|
|
#endif
|
|
|
|
return directory;
|
|
}
|
|
|
|
static int widget_print_all_filenames( struct widget_dirent **filenames, int n,
|
|
int top_left, int current,
|
|
const char *dir )
|
|
{
|
|
int i;
|
|
int error;
|
|
|
|
/* Give us a clean box to start with */
|
|
error = widget_dialog_with_border( 1, 2, 30, 22 );
|
|
if( error ) return error;
|
|
|
|
widget_printstring( 10, 16, WIDGET_COLOUR_TITLE, title );
|
|
if( widget_stringwidth( dir ) > 223 ) {
|
|
char buffer[128];
|
|
int prefix = widget_stringwidth( "..." ) + 1;
|
|
while( widget_stringwidth( dir ) > 223 - prefix ) dir++;
|
|
snprintf( buffer, sizeof( buffer ), "...%s", dir );
|
|
widget_print_title( 24, WIDGET_COLOUR_FOREGROUND, buffer );
|
|
} else {
|
|
widget_print_title( 24, WIDGET_COLOUR_FOREGROUND, dir );
|
|
}
|
|
|
|
if( top_left ) widget_up_arrow( 1, 5, WIDGET_COLOUR_FOREGROUND );
|
|
|
|
/* Print the filenames, mostly normally, but with the currently
|
|
selected file inverted */
|
|
for( i = top_left; i < n && i < top_left + ENTRIES_PER_SCREEN; i++ ) {
|
|
if( i == current ) {
|
|
widget_print_filename( filenames[i], i-top_left, 1 );
|
|
} else {
|
|
widget_print_filename( filenames[i], i-top_left, 0 );
|
|
}
|
|
}
|
|
|
|
if( is_saving )
|
|
{
|
|
widget_printstring( 12, 22 * 8, WIDGET_COLOUR_FOREGROUND,
|
|
"\012RETURN\001 = select" );
|
|
widget_printstring_right( 244, 22 * 8, WIDGET_COLOUR_FOREGROUND,
|
|
"\012TAB\001 = enter name" );
|
|
}
|
|
|
|
if( i < n )
|
|
widget_down_arrow( 1, is_saving ? 20 : 22, WIDGET_COLOUR_FOREGROUND );
|
|
|
|
/* Display that lot */
|
|
widget_display_lines( 2, 22 );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Print a filename onto the dialog box */
|
|
static int widget_print_filename( struct widget_dirent *filename, int position,
|
|
int inverted )
|
|
{
|
|
char buffer[64], suffix[64], *dot = 0;
|
|
int width, suffix_width = 0;
|
|
int dir = S_ISDIR( filename->mode );
|
|
int truncated = 0, suffix_truncated = 0;
|
|
|
|
#define FILENAME_WIDTH 112
|
|
#define MAX_SUFFIX_WIDTH 56
|
|
|
|
int x = (position & 1) ? 132 : 16,
|
|
y = 40 + (position >> 1) * 8;
|
|
|
|
int foreground = WIDGET_COLOUR_FOREGROUND,
|
|
|
|
background = inverted ? WIDGET_COLOUR_HIGHLIGHT
|
|
: WIDGET_COLOUR_BACKGROUND;
|
|
|
|
widget_rectangle( x, y, FILENAME_WIDTH, 8, background );
|
|
|
|
strncpy( buffer, filename->name, sizeof( buffer ) - dir - 1);
|
|
buffer[sizeof( buffer ) - dir - 1] = '\0';
|
|
|
|
if (dir)
|
|
dir = widget_charwidth( FUSE_DIR_SEP_CHR );
|
|
else {
|
|
/* get filename extension */
|
|
dot = strrchr( filename->name, '.' );
|
|
|
|
/* if .gz or .bz2, we want the previous component too */
|
|
if( dot &&( !strcasecmp( dot, ".gz" ) || !strcasecmp( dot, ".bz2" ) ) ) {
|
|
char *olddot = dot;
|
|
*olddot = '\0';
|
|
dot = strrchr( filename->name, '.' );
|
|
*olddot = '.';
|
|
if (!dot)
|
|
dot = olddot;
|
|
}
|
|
|
|
/* if the dot is at the start of the name, ignore it */
|
|
if( dot == filename->name )
|
|
dot = 0;
|
|
}
|
|
|
|
if( dot ) {
|
|
/* split filename at extension separator */
|
|
if( dot - filename->name < sizeof( buffer ) )
|
|
buffer[dot - filename->name] = '\0';
|
|
|
|
/* get extension width (for display purposes) */
|
|
snprintf( suffix, sizeof( suffix ), "%s", dot );
|
|
while( ( suffix_width = ( dot && !dir )
|
|
? widget_stringwidth( suffix ) : 0 ) > 110 ) {
|
|
suffix_truncated = 1;
|
|
suffix[strlen( suffix ) - 1] = '\0';
|
|
}
|
|
}
|
|
|
|
while( ( width = widget_stringwidth( buffer ) ) >=
|
|
FILENAME_WIDTH - dir - ( dot ? truncated + suffix_width : 0 ) ) {
|
|
truncated = 2;
|
|
if( suffix_width >= MAX_SUFFIX_WIDTH ) {
|
|
suffix_truncated = 2;
|
|
suffix[strlen (suffix) - 1] = '\0';
|
|
suffix_width = widget_stringwidth (suffix);
|
|
}
|
|
else
|
|
buffer[strlen (buffer) - 1] = '\0';
|
|
}
|
|
if( dir )
|
|
strcat (buffer, FUSE_DIR_SEP_STR );
|
|
|
|
widget_printstring( x + 1, y, foreground, buffer );
|
|
if( truncated )
|
|
widget_rectangle( x + width + 2, y, 1, 8, 4 );
|
|
if( dot )
|
|
widget_printstring( x + width + 2 + truncated, y,
|
|
foreground ^ 2, suffix );
|
|
if( suffix_truncated )
|
|
widget_rectangle( x + FILENAME_WIDTH, y, 1, 8, 4 );
|
|
|
|
return 0;
|
|
}
|
|
#endif /* ifndef AMIGA */
|
|
|
|
#ifdef WIN32
|
|
static void
|
|
widget_filesel_chdrv( void )
|
|
{
|
|
char *fn;
|
|
|
|
if( chdir( widget_filenames[ current_file ]->name ) ) {
|
|
ui_error( UI_ERROR_ERROR, "Could not change directory" );
|
|
return;
|
|
}
|
|
|
|
is_drivesel = 0;
|
|
fn = widget_getcwd();
|
|
widget_scan( fn ); free( fn );
|
|
new_current_file = 0;
|
|
/* Force a redisplay of all filenames */
|
|
current_file = 1; top_left_file = 1;
|
|
}
|
|
|
|
static void
|
|
widget_filesel_drvlist( void )
|
|
{
|
|
is_drivesel = 1;
|
|
widget_scan( NULL );
|
|
new_current_file = 0;
|
|
/* Force a redisplay of all filenames */
|
|
current_file = 1; top_left_file = 1;
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
static int
|
|
widget_filesel_chdir( void )
|
|
{
|
|
char *fn, *ptr;
|
|
|
|
/* Get the new directory name */
|
|
fn = widget_getcwd();
|
|
if( fn == NULL ) {
|
|
widget_end_widget( WIDGET_FINISHED_CANCEL );
|
|
return 1;
|
|
}
|
|
ptr = fn;
|
|
fn = realloc( fn,
|
|
( strlen( fn ) + 1 + strlen( widget_filenames[ current_file ]->name ) +
|
|
1 ) * sizeof(char)
|
|
);
|
|
if( fn == NULL ) {
|
|
free( ptr );
|
|
widget_end_widget( WIDGET_FINISHED_CANCEL );
|
|
return 1;
|
|
}
|
|
#ifndef GEKKO
|
|
/* Wii getcwd() already has the slash on the end */
|
|
strcat( fn, FUSE_DIR_SEP_STR );
|
|
#endif /* #ifndef GEKKO */
|
|
strcat( fn, widget_filenames[ current_file ]->name );
|
|
|
|
/*
|
|
in Win32 errno resulting from chdir on file is EINVAL which may mean many things
|
|
this will not be fixed in mingw - must use native function instead
|
|
http://thread.gmane.org/gmane.comp.gnu.mingw.user/9197
|
|
*/
|
|
|
|
if( chdir( fn ) == -1 ) {
|
|
#ifndef WIN32
|
|
if( errno == ENOTDIR ) {
|
|
#else /* #ifndef WIN32 */
|
|
if( GetFileAttributes( fn ) != FILE_ATTRIBUTE_DIRECTORY ) {
|
|
#endif /* #ifndef WIN32 */
|
|
widget_filesel_name = fn; fn = NULL;
|
|
if( exit_all_widgets ) {
|
|
widget_end_all( WIDGET_FINISHED_OK );
|
|
} else {
|
|
widget_end_widget( WIDGET_FINISHED_OK );
|
|
}
|
|
}
|
|
} else {
|
|
widget_scan( fn );
|
|
new_current_file = 0;
|
|
/* Force a redisplay of all filenames */
|
|
current_file = 1; top_left_file = 1;
|
|
}
|
|
|
|
free( fn );
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
widget_filesel_keyhandler( input_key key )
|
|
{
|
|
#if !defined AMIGA && !defined __MORPHOS__
|
|
char *fn, *ptr;
|
|
char *dirtitle;
|
|
#endif
|
|
|
|
/* If there are no files (possible on the Wii), can't really do anything */
|
|
if( widget_numfiles == 0 ) {
|
|
if( key == INPUT_KEY_Escape ) widget_end_widget( WIDGET_FINISHED_CANCEL );
|
|
return;
|
|
}
|
|
|
|
#if defined AMIGA || defined __MORPHOS__
|
|
if( exit_all_widgets ) {
|
|
widget_end_all( err );
|
|
} else {
|
|
widget_end_widget( err );
|
|
}
|
|
#else /* ifndef AMIGA */
|
|
|
|
new_current_file = current_file;
|
|
|
|
switch(key) {
|
|
|
|
#if 0
|
|
case INPUT_KEY_Resize: /* Fake keypress used on window resize */
|
|
widget_dialog_with_border( 1, 2, 30, 20 );
|
|
widget_print_all_filenames( widget_filenames, widget_numfiles,
|
|
top_left_file, current_file );
|
|
break;
|
|
#endif
|
|
|
|
case INPUT_KEY_Escape:
|
|
case INPUT_JOYSTICK_FIRE_2:
|
|
widget_end_widget( WIDGET_FINISHED_CANCEL );
|
|
break;
|
|
|
|
case INPUT_KEY_Left:
|
|
case INPUT_KEY_5:
|
|
case INPUT_KEY_h:
|
|
case INPUT_JOYSTICK_LEFT:
|
|
if( current_file > 0 ) new_current_file--;
|
|
break;
|
|
|
|
case INPUT_KEY_Down:
|
|
case INPUT_KEY_6:
|
|
case INPUT_KEY_j:
|
|
case INPUT_JOYSTICK_DOWN:
|
|
if( current_file+2 < widget_numfiles ) new_current_file += 2;
|
|
break;
|
|
|
|
case INPUT_KEY_Up:
|
|
case INPUT_KEY_7: /* Up */
|
|
case INPUT_KEY_k:
|
|
case INPUT_JOYSTICK_UP:
|
|
if( current_file > 1 ) new_current_file -= 2;
|
|
break;
|
|
|
|
case INPUT_KEY_Right:
|
|
case INPUT_KEY_8:
|
|
case INPUT_KEY_l:
|
|
case INPUT_JOYSTICK_RIGHT:
|
|
if( current_file < widget_numfiles-1 ) new_current_file++;
|
|
break;
|
|
|
|
case INPUT_KEY_Page_Up:
|
|
new_current_file = ( current_file > ENTRIES_PER_SCREEN ) ?
|
|
current_file - ENTRIES_PER_SCREEN :
|
|
0;
|
|
break;
|
|
|
|
case INPUT_KEY_Page_Down:
|
|
new_current_file = current_file + ENTRIES_PER_SCREEN;
|
|
if( new_current_file >= widget_numfiles )
|
|
new_current_file = widget_numfiles - 1;
|
|
break;
|
|
|
|
case INPUT_KEY_Home:
|
|
new_current_file = 0;
|
|
break;
|
|
|
|
case INPUT_KEY_End:
|
|
new_current_file = widget_numfiles - 1;
|
|
break;
|
|
|
|
case INPUT_KEY_Tab:
|
|
if( is_saving ) {
|
|
widget_text_t text_data;
|
|
text_data.title = title;
|
|
text_data.allow = WIDGET_INPUT_ASCII;
|
|
text_data.max_length = 30;
|
|
text_data.text[0] = 0;
|
|
if( widget_do_text( &text_data ) ||
|
|
!widget_text_text || !*widget_text_text )
|
|
break;
|
|
if( !compat_is_absolute_path( widget_text_text ) ) {
|
|
/* relative name */
|
|
/* Get current dir name and allocate space for the leafname */
|
|
fn = widget_getcwd();
|
|
ptr = fn;
|
|
if( fn )
|
|
fn = realloc( fn, strlen( fn ) + strlen( widget_text_text ) + 2 );
|
|
if( !fn ) {
|
|
free( ptr );
|
|
widget_end_widget( WIDGET_FINISHED_CANCEL );
|
|
return;
|
|
}
|
|
/* Append the leafname and return it */
|
|
strcat( fn, FUSE_DIR_SEP_STR );
|
|
strcat( fn, widget_text_text );
|
|
} else { /* absolute name */
|
|
fn = utils_safe_strdup( widget_text_text );
|
|
}
|
|
widget_filesel_name = fn;
|
|
if( exit_all_widgets ) {
|
|
widget_end_all( WIDGET_FINISHED_OK );
|
|
} else {
|
|
widget_end_widget( WIDGET_FINISHED_OK );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case INPUT_KEY_Return:
|
|
case INPUT_KEY_KP_Enter:
|
|
case INPUT_JOYSTICK_FIRE_1:
|
|
#ifdef WIN32
|
|
if( is_drivesel ) {
|
|
widget_filesel_chdrv();
|
|
} else if( is_rootdir &&
|
|
!strcmp( widget_filenames[ current_file ]->name, ".." ) ) {
|
|
widget_filesel_drvlist();
|
|
} else {
|
|
#endif /* #ifdef WIN32 */
|
|
if( widget_filesel_chdir() ) return;
|
|
#ifdef WIN32
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
break;
|
|
|
|
default: /* Keep gcc happy */
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef WIN32
|
|
if( is_drivesel ) {
|
|
dirtitle = utils_safe_strdup( "Drive selection" );
|
|
} else {
|
|
#endif /* #ifdef WIN32 */
|
|
dirtitle = widget_getcwd();
|
|
#ifdef WIN32
|
|
}
|
|
#endif /* #ifdef WIN32 */
|
|
|
|
/* If we moved the cursor */
|
|
if( new_current_file != current_file ) {
|
|
|
|
/* If we've got off the top or bottom of the currently displayed
|
|
file list, then reset the top-left corner and display the whole
|
|
thing */
|
|
if( new_current_file < top_left_file ) {
|
|
|
|
top_left_file = new_current_file & ~1;
|
|
widget_print_all_filenames( widget_filenames, widget_numfiles,
|
|
top_left_file, new_current_file, dirtitle );
|
|
|
|
} else if( new_current_file >= top_left_file+ENTRIES_PER_SCREEN ) {
|
|
|
|
top_left_file = new_current_file & ~1;
|
|
top_left_file -= ENTRIES_PER_SCREEN - 2;
|
|
widget_print_all_filenames( widget_filenames, widget_numfiles,
|
|
top_left_file, new_current_file, dirtitle );
|
|
|
|
} else {
|
|
|
|
/* Otherwise, print the current file uninverted and the
|
|
new current file inverted */
|
|
|
|
widget_print_filename( widget_filenames[ current_file ],
|
|
current_file - top_left_file, 0 );
|
|
|
|
widget_print_filename( widget_filenames[ new_current_file ],
|
|
new_current_file - top_left_file, 1 );
|
|
|
|
widget_display_lines( 2, 21 );
|
|
}
|
|
|
|
/* Reset the current file marker */
|
|
current_file = new_current_file;
|
|
|
|
}
|
|
|
|
free( dirtitle );
|
|
#endif /* ifdef AMIGA */
|
|
}
|