grafX2/src/filesel.c
2018-12-09 21:04:34 +01:00

2442 lines
78 KiB
C

/* vim:expandtab:ts=2 sw=2:
*/
/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2018 Thomas Bernard
Copyright 2014 Sergii Pylypenko
Copyright 2011 Pawel Góralski
Copyright 2009 Franck Charlet
Copyright 2008 Peter Gordon
Copyright 2008 Yves Rizoud
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 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; version 2
of the License.
Grafx2 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 Grafx2; if not, see <http://www.gnu.org/licenses/>
*/
#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
#include <proto/dos.h>
#include <sys/types.h>
#elif defined (__MINT__)
#include <mint/sysbind.h>
#elif defined(WIN32)
#include <windows.h>
#include <commdlg.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#ifdef _MSC_VER
#include <stdio.h>
#define strdup _strdup
#if _MSC_VER < 1900
#define snprintf _snprintf
#endif
#else
#include <strings.h>
#include <unistd.h>
#endif
#include <ctype.h>
#include <wctype.h>
#include <sys/types.h>
#include "const.h"
#include "struct.h"
#include "global.h"
#include "misc.h"
#include "errors.h"
#include "io.h"
#include "windows.h"
#include "screen.h"
#include "loadsave.h"
#include "mountlist.h"
#include "engine.h"
#include "readline.h"
#include "input.h"
#include "help.h"
#include "unicode.h"
#include "filesel.h"
#define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de
// fichier non sélectionné
#define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de
// répertoire non sélectionné
#define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne
// non sélectionnée
#define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de
// fichier sélectionnée
#define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de
// repértoire sélectionnée
#define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne
// sélectionnée
// -- Native fileselector for WIN32
// Returns 0 if all ok, something else if failed
byte Native_filesel(byte load)
{
//load = load;
#if WIN32
OPENFILENAME ofn;
char szFileName[MAX_PATH] = "";
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = GFX2_Get_Window_Handle();
ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0");
#ifdef UNICODE
#else
ofn.lpstrFile = szFileName;
#endif
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER;
if(load) ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = TEXT("txt");
if(load)
{
if (GetOpenFileName(&ofn))
// Do something usefull with the filename stored in szFileName
return 0;
else
// error - check if its just user pressing cancel or something else
return CommDlgExtendedError();
} else if(GetSaveFileName(&ofn)) {
return 0;
} else {
// Check if cancel
return CommDlgExtendedError();
}
#else
(void)load; // unused
#if 0
/* if the native fileselector is used, we should implement it where needed
* OS X ? GTK ? etc. */
#ifndef __linux__ // This makes no sense on X11-oriented platforms. Nothing is really native there.
#warning "EXPERIMENTAL function for native fileselector not available for this platform!"
#endif
#endif
return 255; // fail !
#endif
}
// -- "Standard" fileselector for other platforms
// -- Fileselector data
static T_Fileselector Filelist;
/// Selector settings to use, for all functions called by Load_or_save
static T_Selector_settings * Selector;
/// Name of the current directory
//static char Selector_directory[1024];
/// Filename (without directory) of the highlighted file
static char Selector_filename[256];
static word Selector_filename_unicode[256];
// Conventions:
//
// * Le fileselect modifie le répertoire courant. Ceci permet de n'avoir
// qu'un findfirst dans le répertoire courant à faire:
/**
* Update T_Fileselector::Nb_files T_Fileselector::Nb_directories T_Fileselector::Nb_elements
* counts.
* Also update the list index T_Fileselector::Index
* @param list the linked list to update
*/
static void Recount_files(T_Fileselector *list)
{
T_Fileselector_item *item;
list->Nb_files=0;
list->Nb_directories=0;
list->Nb_elements=0;
for (item = list->First; item != NULL; item = item->Next)
{
if (item->Type == FSOBJECT_FILE)
list->Nb_files ++;
else
list->Nb_directories ++;
list->Nb_elements ++;
}
if (list->Index)
{
free(list->Index);
list->Index = NULL;
}
if (list->Nb_elements>0)
{
int i;
list->Index = (T_Fileselector_item **) malloc(list->Nb_elements * sizeof(T_Fileselector_item *));
if (list->Index)
{
// Fill the index
for (item = list->First, i=0; item != NULL; item = item->Next, i++)
{
list->Index[i] = item;
}
}
// If the malloc failed, we're probably in trouble, but I don't know
// how to recover from that..I'll just make the index bulletproof.
}
}
/**
* This function free all item in the list, but not the list itself.
* @param list the linked list
*/
void Free_fileselector_list(T_Fileselector *list)
{
// Pointeur temporaire de destruction
T_Fileselector_item * temp_item;
while (list->First!=NULL)
{
// On mémorise l'adresse du premier élément de la liste
temp_item =list->First;
// On fait avancer la tête de la liste
list->First=list->First->Next;
// Et on efface l'ancien premier élément de la liste
free(temp_item->Unicode_full_name);
free(temp_item->Unicode_short_name);
free(temp_item);
temp_item = NULL;
}
Recount_files(list);
}
word * Format_filename_unicode(const word * fname, word max_length, int type)
{
static word result[40];
int c;
int other_cursor;
int pos_last_dot;
// safety
if (max_length>40)
max_length=40;
if (Unicode_char_strcmp(fname,PARENT_DIR)==0)
{
Unicode_char_strlcpy(result, "\x11 PARENT DIRECTORY", 40);
// Append spaces
for (c=18; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
}
else if (fname[0]=='.' || type==1 || type==2)
{
// Files ".something" or drives or directories: Aligned left on (max_length-1) chars max
// Initialize as all spaces
for (c=0; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
for (c=0;fname[c]!='\0' && c < max_length-1;c++)
result[c]=fname[c];
// A special character indicates the filename is truncated
if (c >= max_length-1)
result[max_length-2]=(byte)ELLIPSIS_CHARACTER;
}
else
{
// Initialize as all spaces
for (c = 0; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
result[max_length-5]='.';
// Look for the last dot in filename
pos_last_dot = Position_last_dot_unicode(fname);
// Copy the part before the dot
for (c=0; c!=pos_last_dot && fname[c]!='\0'; c++)
{
if (c > max_length-6)
{
result[max_length-6]=(byte)ELLIPSIS_CHARACTER;
break;
}
result[c]=fname[c];
}
// Ensuite on recopie la partie qui suit le point (si nécessaire):
if (pos_last_dot != -1)
{
for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++)
result[other_cursor]=fname[c];
}
}
return result;
}
char * Format_filename(const char * fname, word max_length, int type)
{
static char result[40];
int c;
int other_cursor;
int pos_last_dot;
#ifdef ENABLE_FILENAMES_ICONV
/* convert file name from UTF8 to ANSI */
char converted_fname[MAX_PATH_CHARACTERS];
{
char * input = (char *)fname;
size_t inbytesleft = strlen(fname);
char * output = converted_fname;
size_t outbytesleft = sizeof(converted_fname)-1;
if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0)
{
*output = '\0';
fname = converted_fname;
}
}
#endif /* ENABLE_FILENAMES_ICONV */
// safety
if (max_length>40)
max_length=40;
if (strcmp(fname,PARENT_DIR)==0)
{
strcpy(result,"\x11 PARENT DIRECTORY");
// Append spaces
for (c=18; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
}
else if (fname[0]=='.' || type==1 || type==2)
{
// Files ".something" or drives or directories: Aligned left on (max_length-1) chars max
// Initialize as all spaces
for (c=0; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
for (c=0;fname[c]!='\0' && c < max_length-1;c++)
result[c]=fname[c];
// A special character indicates the filename is truncated
if (c >= max_length-1)
result[max_length-2]=ELLIPSIS_CHARACTER;
}
else
{
// Initialize as all spaces
for (c = 0; c<max_length-1; c++)
result[c]=' ';
result[c]='\0';
result[max_length-5]='.';
// Look for the last dot in filename
pos_last_dot = Position_last_dot(fname);
// Copy the part before the dot
for (c=0; c!=pos_last_dot && fname[c]!='\0'; c++)
{
if (c > max_length-6)
{
result[max_length-6]=ELLIPSIS_CHARACTER;
break;
}
result[c]=fname[c];
}
// Ensuite on recopie la partie qui suit le point (si nécessaire):
if (pos_last_dot != -1)
{
for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++)
result[other_cursor]=fname[c];
}
}
return result;
}
/**
* Add an item to the file selector linked list
* @param list the linked list
* @param full_name the file name
* @param short_name the file name truncated to display in the file selector
* @param type the type of the item : 0 = File, 1 = Directory, 2 = Drive
* @param icon the icon for the item
* @return a pointer to the newly added item
* @return NULL in case of error
*/
T_Fileselector_item * Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, enum FSOBJECT_TYPE type, enum ICON_TYPES icon)
{
// Working element
T_Fileselector_item * temp_item;
size_t full_name_len, short_name_len;
full_name_len = strlen(full_name) + 1;
short_name_len = strlen(short_name) + 1;
// Allocate enough room for one struct + the visible label
temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+full_name_len);
if (temp_item == NULL) // memory allocation error
return NULL;
memset(temp_item, 0, sizeof(T_Fileselector_item));
if (short_name_len > sizeof(temp_item->Short_name))
short_name_len = sizeof(temp_item->Short_name) - 1; // without terminating 0
// Initialize element
memcpy(temp_item->Short_name,short_name,short_name_len);
memcpy(temp_item->Full_name,full_name,full_name_len);
temp_item->Type = type;
temp_item->Icon = icon;
// Doubly-linked
temp_item->Next =list->First;
temp_item->Previous=NULL;
if (list->First!=NULL)
list->First->Previous=temp_item;
// Put new element at the beginning
list->First=temp_item;
return temp_item;
}
///
/// Checks if a file has the requested file extension.
/// The extension string can end with a ';' (remainder is ignored).
/// This function allows wildcard '?', and '*' if it's the only character.
int Check_extension(const char *filename_ext, const char * filter)
{
int c;
if (filter[0] == '*')
return 1;
// filename without extension
if (filename_ext == NULL || filename_ext[0] == '\0')
return (filter[0] == '\0' || filter[0] == ';');
// Vérification caractère par caractère, case-insensitive.
for (c = 0; !(filter[c] == '\0' || filter[c] == ';'); c++)
{
if (filter[c] != '?' &&
tolower(filter[c]) != tolower(filename_ext[c]))
return 0;
}
return filename_ext[c] == '\0';
}
// -- Lecture d'une liste de fichiers ---------------------------------------
struct Read_dir_pdata
{
T_Fileselector *list;
const char * filter;
};
static void Read_dir_callback(void * pdata, const char *file_name, const word *unicode_name, byte is_file, byte is_directory, byte is_hidden)
{
T_Fileselector_item * item;
struct Read_dir_pdata * p = (struct Read_dir_pdata *)pdata;
if (p == NULL) // error !
return;
// Ignore 'current directory' entry
if ( !strcmp(file_name, "."))
return;
// entries tagged "directory" :
if (is_directory)
{
// On Windows, the presence of a "parent directory" entry has proven
// unreliable on non-physical drives :
// Sometimes it's missing, sometimes it's present even at root...
// We skip it here and add a specific check after the loop
#if defined(WIN32)
if (!strcmp(file_name, PARENT_DIR))
return;
#endif
// Don't display hidden file, unless requested by options
if (!Config.Show_hidden_directories && is_hidden)
return;
// Add to list
item = Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 1), FSOBJECT_DIR, ICON_NONE);
if (item != NULL && unicode_name != NULL)
{
item->Unicode_full_name = Unicode_strdup(unicode_name);
item->Unicode_short_name = Unicode_strdup(Format_filename_unicode(unicode_name, 19, 1));
}
p->list->Nb_directories++;
}
else if (is_file && // It's a file
(Config.Show_hidden_files || !is_hidden))
{
const char * ext = p->filter;
const char * file_name_ext = NULL;
#ifdef WIN32
char long_ext[16];
#endif
int pos_last_dot = Position_last_dot(file_name);
if (pos_last_dot >= 0)
file_name_ext = file_name + pos_last_dot + 1;
#ifdef WIN32
if (unicode_name && unicode_name[0] != 0)
{
pos_last_dot = Position_last_dot_unicode(unicode_name);
if (pos_last_dot >= 0)
{
int i;
pos_last_dot++;
for (i = 0; i < (int)sizeof(long_ext) - 1; i++)
long_ext[i] = (unicode_name[pos_last_dot + i] < 256) ? unicode_name[pos_last_dot + i] : '?';
long_ext[i] = '\0';
file_name_ext = long_ext;
}
}
#endif
while (ext!=NULL)
{
if (Check_extension(file_name_ext, ext))
{
// Add to list
item = Add_element_to_list(p->list, file_name, Format_filename(file_name, 19, 0), FSOBJECT_FILE, ICON_NONE);
if (item != NULL && unicode_name != NULL)
{
item->Unicode_full_name = Unicode_strdup(unicode_name);
item->Unicode_short_name = Unicode_strdup(Format_filename_unicode(unicode_name, 19, 0));
}
p->list->Nb_files++;
// Stop searching
break;
}
else
{
ext = strchr(ext, ';');
if (ext)
ext++;
}
}
}
}
void Read_list_of_files(T_Fileselector *list, byte selected_format)
// Cette procédure charge dans la liste chainée les fichiers dont l'extension
// correspond au format demandé.
{
struct Read_dir_pdata callback_data;
const char * current_path = NULL;
char curdir[MAX_PATH_CHARACTERS];
#if defined (__MINT__)
T_Fileselector_item *item=0;
bool bFound=false;
#endif
callback_data.list = list;
// Tout d'abord, on déduit du format demandé un filtre à utiliser:
callback_data.filter = Get_fileformat(selected_format)->Extensions;
// Ensuite, on vide la liste actuelle:
Free_fileselector_list(list);
// Après effacement, il ne reste ni fichier ni répertoire dans la liste
// On lit tous les répertoires:
current_path = Get_current_directory(curdir, NULL, MAX_PATH_CHARACTERS);
For_each_directory_entry(current_path, &callback_data, Read_dir_callback);
// Now here's OS-specific code to determine if "parent directory" entry
// should appear.
#if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__)
// Amiga systems: always
Add_element_to_list(list, PARENT_DIR, Format_filename(PARENT_DIR,19,1), FSOBJECT_DIR, ICON_NONE);
list->Nb_directories ++;
#elif defined (WIN32)
// Windows :
if (((current_path[0]>='a'&&current_path[0]<='z')||(current_path[0]>='A'&&current_path[0]<='Z')) &&
current_path[1]==':' &&
(
(current_path[2]=='\0') ||
(current_path[2]=='/'&&current_path[3]=='\0') ||
(current_path[2]=='\\'&&current_path[3]=='\0')
))
{
// Path is X:\ or X:/ or X:
// so don't display parent directory
}
else
{
Add_element_to_list(list, PARENT_DIR, Format_filename(PARENT_DIR,19,1), FSOBJECT_DIR, ICON_NONE);
list->Nb_directories ++;
}
#elif defined (__MINT__)
// check if ".." exists if not add it
// FreeMinT lists ".." already, but this is not so for TOS
// simply adding it will cause double PARENT_DIR under FreeMiNT
bFound= false;
for (item = list->First; item != NULL; item = item->Next)
{
if (item->Type == FSOBJECT_DIR && (strncmp(item->Full_name, PARENT_DIR, (sizeof(char)*2))==0) )
{
bFound=true;
break;
}
}
if(!bFound)
{
Add_element_to_list(list,PARENT_DIR,Format_filename(PARENT_DIR,19,1),FSOBJECT_DIR,ICON_NONE); // add if not present
list->Nb_directories ++;
}
#endif
current_path = NULL;
if (list->Nb_files==0 && list->Nb_directories==0)
{
// This can happen on some empty network drives.
// Add a dummy entry because the fileselector doesn't
// seem to support empty list.
Add_element_to_list(list, ".",Format_filename(".",19,1),FSOBJECT_DIR,ICON_NONE);
}
Recount_files(list);
}
#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
void bstrtostr( BSTR in, STRPTR out, TEXT max )
{
STRPTR iptr;
dword i;
dword len;
#if defined(__AROS__)
iptr = AROS_BSTR_ADDR( in );
len = AROS_BSTR_strlen( in );
#else
iptr = BADDR( in );
len = iptr[0];
iptr++;
#endif
if( max > len ) max = len;
for( i=0; i<max; i++ , iptr++ ) out[i] = *iptr;
out[i] = 0;
}
#endif
// -- Lecture d'une liste de lecteurs / volumes -----------------------------
void Read_list_of_drives(T_Fileselector *list, byte name_length)
{
#if defined(__MINT__)
char drive_name[]="A:\\";
unsigned long drive_bits=0;
int drive_index=0;
int bit_index=0;
#endif
// Empty the current content of fileselector:
Free_fileselector_list(list);
// Reset number of items
list->Nb_files=0;
list->Nb_directories=0;
#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
{
struct DosList *dl;
char tmp[256];
dl = LockDosList( LDF_VOLUMES | LDF_ASSIGNS | LDF_READ );
if( dl )
{
while( ( dl = NextDosEntry( dl, LDF_VOLUMES | LDF_ASSIGNS | LDF_READ ) ) )
{
bstrtostr( dl->dol_Name, tmp, 254 );
strcat( tmp, ":" );
Add_element_to_list(list, tmp, Format_filename(tmp, name_length, 2), FSOBJECT_DRIVE, ICON_NONE );
list->Nb_directories++;
}
UnLockDosList( LDF_VOLUMES | LDF_ASSIGNS | LDF_READ );
}
}
#elif defined (WIN32)
{
char drive_name[]="A:\\";
int drive_bits = GetLogicalDrives();
int drive_index;
int bit_index;
byte icon;
// Sous Windows, on a la totale, presque aussi bien que sous DOS:
drive_index = 0;
for (bit_index=0; bit_index<26 && drive_index<23; bit_index++)
{
if ( (1 << bit_index) & drive_bits )
{
// On a ce lecteur, il faut maintenant déterminer son type "physique".
// pour profiter des jolies icones de X-man.
char drive_path[]="A:\\";
// Cette API Windows est étrange, je dois m'y faire...
drive_path[0]='A'+bit_index;
switch (GetDriveTypeA(drive_path))
{
case DRIVE_CDROM:
icon=ICON_CDROM;
break;
case DRIVE_REMOTE:
icon=ICON_NETWORK;
break;
case DRIVE_REMOVABLE:
icon=ICON_FLOPPY_3_5;
break;
case DRIVE_FIXED:
icon=ICON_HDD;
break;
default:
icon=ICON_NETWORK;
break;
}
drive_name[0]='A'+bit_index;
Add_element_to_list(list, drive_name, Format_filename(drive_name,name_length-1,2), FSOBJECT_DRIVE, icon);
list->Nb_directories++;
drive_index++;
}
}
}
#elif defined(__MINT__)
drive_bits = Drvmap(); //get drive map bitfield
for (bit_index=0; bit_index<32; bit_index++)
{
if ( (1 << bit_index) & drive_bits )
{
drive_name[0]='A'+bit_index;
Add_element_to_list(list, drive_name,Format_filename(drive_name,name_length,2),FSOBJECT_DRIVE,ICON_NONE);
list->Nb_directories++;
drive_index++;
}
}
#else
{
//Sous les différents unix, on va mettre
// un disque dur qui pointera vers la racine,
// et un autre vers le home directory de l'utilisateur.
// Ensuite on utilise read_file_system_list pour compléter
struct mount_entry* mount_points_list;
struct mount_entry* next;
char * home_dir = getenv("HOME");
Add_element_to_list(list, "/", Format_filename("/",name_length-1,2), FSOBJECT_DRIVE, ICON_HDD);
list->Nb_directories++;
if(home_dir)
{
Add_element_to_list(list, home_dir, Format_filename(home_dir, name_length, 2), FSOBJECT_DRIVE, ICON_NONE);
list->Nb_directories++;
}
mount_points_list = read_file_system_list(0);
while(mount_points_list != NULL)
{
byte icon = ICON_NONE;
if (mount_points_list->me_remote)
icon = ICON_NETWORK;
else if (strcmp(mount_points_list->me_type, "cd9660") == 0)
icon = ICON_CDROM;
else if (strcmp(mount_points_list->me_type, "nfs") == 0)
icon = ICON_NETWORK;
else if (strcmp(mount_points_list->me_type, "msdos") == 0)
icon = ICON_FLOPPY_3_5; // Only a guess...
else if (strcmp(mount_points_list->me_type, "ext2fs") == 0)
icon = ICON_HDD; // Only a guess...
else if (strcmp(mount_points_list->me_type, "hfs") == 0)
icon = ICON_HDD; // Only a guess...
else if (strcmp(mount_points_list->me_type, "ufs") == 0)
icon = ICON_HDD; // Only a guess...
else if (strcmp(mount_points_list->me_type, "zfs") == 0)
icon = ICON_HDD; // Only a guess...
GFX2_Log(GFX2_DEBUG, "dummy=%u type=%s path=%s icon=%d\n", mount_points_list->me_dummy, mount_points_list->me_type, mount_points_list->me_mountdir, (int)icon);
if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home"))
{
Add_element_to_list(list, mount_points_list->me_mountdir,
Format_filename(mount_points_list->me_mountdir, name_length + (icon==ICON_NONE?0:-1), 2), FSOBJECT_DRIVE, icon);
list->Nb_directories++;
}
next = mount_points_list -> me_next;
if (mount_points_list->me_type_malloced)
{
free(mount_points_list -> me_type);
}
free(mount_points_list -> me_devname);
free(mount_points_list -> me_mountdir);
free(mount_points_list);
mount_points_list = next;
}
}
#endif
Recount_files(list);
}
// Comparison of file names:
#ifdef WIN32
// case-insensitive
#define FILENAME_COMPARE strcasecmp
#else
// case-sensitive
#define FILENAME_COMPARE strcmp
#endif
/**
* Sort a file/directory list.
* The sord is done in that order :
* Directories first, in alphabetical order,
* then Files, in alphabetical order.
*
* List counts and index are updated.
* @param list the linked list
*/
void Sort_list_of_files(T_Fileselector *list)
{
byte list_is_sorted; // Booléen "La liste est triée"
byte need_swap; // Booléen "Il faut inverser les éléments"
T_Fileselector_item * prev_item;
T_Fileselector_item * current_item;
T_Fileselector_item * next_item;
T_Fileselector_item * next_to_next_item;
// Check there are at least two elements before sorting
if (list->First && list->First->Next)
{
do
{
// Par défaut, on considère que la liste est triée
list_is_sorted=1;
current_item=list->First;
next_item=current_item->Next;
while ( (current_item!=NULL) && (next_item!=NULL) )
{
// On commence par supposer qu'il n'y pas pas besoin d'inversion
need_swap=0;
// Ensuite, on vérifie si les deux éléments sont bien dans l'ordre ou
// non:
// Drives go at the top of the list, and files go after them
if ( (int)current_item->Type < (int)next_item->Type )
need_swap=1;
// If both elements have the same type, compare the file names, if
// current is alphabetically before, we need to swap, unless it is
// parent directory, which should always go first
else if ( (current_item->Type==next_item->Type) &&
(((FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) &&
(FILENAME_COMPARE(current_item->Full_name, PARENT_DIR) != 0)) ||
(FILENAME_COMPARE(next_item->Full_name, PARENT_DIR) == 0))
)
need_swap=1;
if (need_swap)
{
// Si les deux éléments nécessitent d'être inversé:
// On les inverses:
// On note avant tout les éléments qui encapsulent nos deux amis
prev_item =current_item->Previous;
next_to_next_item=next_item->Next;
// On permute le chaînage des deux éléments entree eux
current_item->Next =next_to_next_item;
current_item->Previous=next_item;
next_item->Next =current_item;
next_item->Previous=prev_item;
// On tente un chaînage des éléments encapsulant les compères:
if (prev_item!=NULL)
prev_item->Next=next_item;
if (next_to_next_item!=NULL)
next_to_next_item->Previous=current_item;
// On fait bien attention à modifier la tête de liste en cas de besoin
if (current_item==list->First)
list->First=next_item;
// Ensuite, on se prépare à étudier les éléments précédents:
current_item=prev_item;
// Et on constate que la liste n'était pas encore génialement triée
list_is_sorted=0;
}
else
{
// Si les deux éléments sont dans l'ordre:
// On passe aux suivants
current_item=current_item->Next;
next_item=next_item->Next;
}
}
}
while (!list_is_sorted);
}
// Force a recount / re-index
Recount_files(list);
}
T_Fileselector_item * Get_item_by_index(T_Fileselector *list, unsigned short index)
{
// Safety
if (list->Nb_elements == 0)
return NULL;
if (index >= list->Nb_elements)
index=list->Nb_elements-1;
if (list->Index)
{
return list->Index[index];
}
else
{
// Index not available.
// Can only happen in case of malloc error.
// Fall back anyway on iterative search
T_Fileselector_item * item = list->First;
for (; index > 0 && item != NULL; index--)
item = item->Next;
return item;
}
}
/**
* Display of the file/directory list items.
* @param list the file list
* @param offset_first offset between the 1st visible file and the first file in list.
* @param selector_offset offset between the 1st visible file and the selected file.
*/
void Display_file_list(T_Fileselector *list, short offset_first,short selector_offset)
{
T_Fileselector_item * current_item;
byte index; // index du fichier qu'on affiche (0 -> 9)
byte text_color;
byte background_color;
// On vérifie s'il y a au moins 1 fichier dans la liste:
if (list->Nb_elements>0)
{
// On commence par chercher à pointer sur le premier fichier visible:
current_item = Get_item_by_index(list, offset_first);
// Pour chacun des 10 éléments inscriptibles à l'écran
for (index=0;index<10;index++)
{
// S'il est sélectionné:
if (!selector_offset)
{
// Si c'est un fichier
if (current_item->Type==0)
text_color=SELECTED_FILE_COLOR;
else
text_color=SELECTED_DIRECTORY_COLOR;
background_color=SELECTED_BACKGROUND_COLOR;
}
else
{
// Si c'est un fichier
if (current_item->Type==0)
text_color=NORMAL_FILE_COLOR;
else
text_color=NORMAL_DIRECTORY_COLOR;
background_color=NORMAL_BACKGROUND_COLOR;
}
// On affiche l'élément
if (current_item->Icon != ICON_NONE)
{
// Name preceded by an icon
Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color);
Window_display_icon_sprite(8,95+index*8,current_item->Icon);
}
else
{
// Name without icon
if (current_item->Unicode_short_name)
Print_in_window_unicode(8,95+index*8,current_item->Unicode_short_name,text_color,background_color);
else
Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color);
}
// On passe à la ligne suivante
selector_offset--;
current_item=current_item->Next;
if (!current_item)
break;
} // End de la boucle d'affichage
} // End du test d'existence de fichiers
}
/**
* Get the label of a list item.
* @param list the file list
* @param offset_first offset between the 1st visible file and the 1st file in list.
* @param selector_offset offset between the 1st visible file and the wanted label.
* @param label pointer to a buffer to receive the label (ANSI)
* @param unicode_label pointer to a buffer to receive the label (Unicode)
* @param type NULL or a pointer to receive the type : 0 = file, 1 = directory, 2 = drive.
*/
static void Get_selected_item(T_Fileselector *list, short offset_first,short selector_offset,char * label,word * unicode_label, enum FSOBJECT_TYPE *type)
{
T_Fileselector_item * current_item;
// On vérifie s'il y a au moins 1 fichier dans la liste:
if (list->Nb_elements>0)
{
// On commence par chercher à pointer sur le premier fichier visible:
// Ensuite, on saute autant d'éléments que le décalage demandé:
current_item = Get_item_by_index(list, offset_first + selector_offset);
// On recopie la chaîne
strcpy(label, current_item->Full_name);
if (unicode_label != NULL)
{
if (current_item->Unicode_full_name)
Unicode_strlcpy(unicode_label, current_item->Unicode_full_name, 256);
else
Unicode_char_strlcpy(unicode_label, current_item->Full_name, 256);
}
if (type != NULL)
*type=current_item->Type;
} // End du test d'existence de fichiers
}
// ----------------- Déplacements dans la liste de fichiers -----------------
void Selector_scroll_down(short * offset_first,short * selector_offset)
// Fait scroller vers le bas le sélecteur de fichier... (si possible)
{
if ( ((*selector_offset)<9)
&& ( (*selector_offset)+1 < Filelist.Nb_elements ) )
// Si la sélection peut descendre
Display_file_list(&Filelist, *offset_first,++(*selector_offset));
else // Sinon, descendre la fenêtre (si possible)
if ((*offset_first)+10<Filelist.Nb_elements)
Display_file_list(&Filelist, ++(*offset_first),*selector_offset);
}
void Selector_scroll_up(short * offset_first,short * selector_offset)
// Fait scroller vers le haut le sélecteur de fichier... (si possible)
{
if ((*selector_offset)>0)
// Si la sélection peut monter
Display_file_list(&Filelist, *offset_first,--(*selector_offset));
else // Sinon, monter la fenêtre (si possible)
if ((*offset_first)>0)
Display_file_list(&Filelist, --(*offset_first),*selector_offset);
}
void Selector_page_down(short * offset_first,short * selector_offset, short lines)
{
if (Filelist.Nb_elements-1>*offset_first+*selector_offset)
{
if (*selector_offset<9)
{
if (Filelist.Nb_elements<10)
{
*offset_first=0;
*selector_offset=Filelist.Nb_elements-1;
}
else *selector_offset=9;
}
else
{
if (Filelist.Nb_elements>*offset_first+18)
*offset_first+=lines;
else
{
*offset_first=Filelist.Nb_elements-10;
*selector_offset=9;
}
}
}
Display_file_list(&Filelist, *offset_first,*selector_offset);
}
void Selector_page_up(short * offset_first,short * selector_offset, short lines)
{
if (*offset_first+*selector_offset>0)
{
if (*selector_offset>0)
*selector_offset=0;
else
{
if (*offset_first>lines)
*offset_first-=lines;
else
*offset_first=0;
}
}
Display_file_list(&Filelist, *offset_first,*selector_offset);
}
void Selector_end(short * offset_first,short * selector_offset)
{
if (Filelist.Nb_elements<10)
{
*offset_first=0;
*selector_offset=Filelist.Nb_elements-1;
}
else
{
*offset_first=Filelist.Nb_elements-10;
*selector_offset=9;
}
Display_file_list(&Filelist, *offset_first,*selector_offset);
}
void Selector_home(short * offset_first,short * selector_offset)
{
Display_file_list(&Filelist, (*offset_first)=0,(*selector_offset)=0);
}
short Compute_click_offset_in_fileselector(void)
/*
Renvoie le décalage dans le sélecteur de fichier sur lequel on a clické.
Renvoie le décalage du dernier fichier si on a clické au delà.
Renvoie -1 si le sélecteur est vide.
*/
{
short computed_offset;
computed_offset=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3;
if (computed_offset>=Filelist.Nb_elements)
computed_offset=Filelist.Nb_elements-1;
return computed_offset;
}
void Display_bookmark(T_Dropdown_button * Button, int bookmark_number)
{
if (Config.Bookmark_directory[bookmark_number])
{
int label_size;
// Libellé
Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light);
label_size=strlen(Config.Bookmark_label[bookmark_number]);
if (label_size<8)
Window_rectangle(Button->Pos_X+3+10+label_size*8,Button->Pos_Y+2,(8-label_size)*8,8,MC_Light);
// Menu apparait sur clic droit
Button->Active_button=RIGHT_SIDE;
// item actifs
Window_dropdown_clear_items(Button);
Window_dropdown_add_item(Button,0,"Set");
Window_dropdown_add_item(Button,1,"Rename");
Window_dropdown_add_item(Button,2,"Clear");
}
else
{
// Libellé
Print_in_window(Button->Pos_X+3+10,Button->Pos_Y+2,"--------",MC_Dark,MC_Light);
// Menu apparait sur clic droit ou gauche
Button->Active_button=RIGHT_SIDE|LEFT_SIDE;
// item actifs
Window_dropdown_clear_items(Button);
Window_dropdown_add_item(Button,0,"Set");
}
}
//------------------------ Chargements et sauvegardes ------------------------
void Print_current_directory(void)
//
// Shows Selector->Directory on 37 chars
//
{
char converted_name[MAX_PATH_CHARACTERS];
int length; // length du répertoire courant
int index; // index de parcours de la chaine complète
strncpy(converted_name,Selector->Directory,sizeof(converted_name));
converted_name[sizeof(converted_name)-1] = '\0';
#ifdef ENABLE_FILENAMES_ICONV
{
/* convert file name from UTF8 to ANSI */
char * input = Selector->Directory;
size_t inbytesleft = strlen(input);
char * output = converted_name;
size_t outbytesleft = sizeof(converted_name)-1;
if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0)
*output = '\0';
}
#endif /* ENABLE_FILENAMES_ICONV */
Window_rectangle(10,84,37*8,8,MC_Light);
if (Selector->Directory_unicode[0] != 0)
{
length=Unicode_strlen(Selector->Directory_unicode);
if (length>MAX_DISPLAYABLE_PATH)
{ // We need to truncate the directory
word temp_name[MAX_DISPLAYABLE_PATH+1]; // truncated name
memcpy(temp_name, Selector->Directory_unicode, 3*2); // first 3 chars "C:\"
temp_name[3] = (byte)ELLIPSIS_CHARACTER;
temp_name[4] = 0;
// next we look for a place to fit everything ;)
for (index=3;index<length;index++)
if ( (Selector->Directory_unicode[index]==PATH_SEPARATOR[0]) &&
(length-index<=MAX_DISPLAYABLE_PATH-4) )
{
// we found the place !
Unicode_strlcpy(temp_name+4,Selector->Directory_unicode+index, MAX_DISPLAYABLE_PATH+1-4);
break;
}
Print_in_window_unicode(10,84,temp_name,MC_Black,MC_Light);
}
else // The string is short enough
Print_in_window_unicode(10,84,Selector->Directory_unicode,MC_Black,MC_Light);
}
else
{
length=strlen(converted_name);
if (length>MAX_DISPLAYABLE_PATH)
{ // We need to truncate the directory
char temp_name[MAX_DISPLAYABLE_PATH+1]; // truncated name
for (index=0;index<3;index++) // copy the first 3 chars "C:\"
temp_name[index]=converted_name[index];
temp_name[3] = ELLIPSIS_CHARACTER;
temp_name[4] = '\0';
// next we look for a place to fit everything ;)
for (index++;index<length;index++)
if ( (converted_name[index]==PATH_SEPARATOR[0]) &&
(length-index<=MAX_DISPLAYABLE_PATH-4) )
{
// we found the place !
strcpy(temp_name+4,converted_name+index);
break;
}
// display truncated string
Print_in_window(10,84,temp_name,MC_Black,MC_Light);
}
else // The string is short enough
Print_in_window(10,84,converted_name,MC_Black,MC_Light);
}
Update_window_area(10,84,37*8,8);
}
//
// Print the current file name
//
void Print_filename_in_fileselector(void)
{
char filename[32];
strncpy(filename, Selector_filename, sizeof(filename));
#ifdef ENABLE_FILENAMES_ICONV
{
char * input = (char *)Selector_filename;
size_t inbytesleft = strlen(Selector_filename);
char * output = filename;
size_t outbytesleft = sizeof(filename)-1;
if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0)
*output = '\0';
}
#endif /* ENABLE_FILENAMES_ICONV */
Window_rectangle(82,48,27*8,8,MC_Light);
if (Selector_filename_unicode[0] != 0)
{
word filename_unicode[32];
Unicode_strlcpy(filename_unicode, Selector_filename_unicode, 28); // 28 including the terminating 0
Print_in_window_unicode(82,48,filename_unicode,MC_Black,MC_Light);
}
else
Print_in_window_limited(82,48,filename,27,MC_Black,MC_Light);
Update_window_area(82,48,27*8,8);
}
/// Type of the selected entry in the file selector.
static enum FSOBJECT_TYPE Selected_type;
/// Displays the file list with sliders, etc.
/// also optionally updates the current file name (Selector_filename)
/// @param Position the current position in the file list
/// @param offset the offset of the selected item in the file list
/// @param button the scrollbar/slider GUI control
/// @param setfilename option to update Selector_filename
static void Prepare_and_display_filelist(short Position, short offset, T_Scroller_button * button, int setfilename)
{
button->Nb_elements=Filelist.Nb_elements;
button->Position=Position;
Compute_slider_cursor_length(button);
Window_draw_slider(button);
// On efface les anciens noms de fichier:
Window_rectangle(8-1,95-1,144+2,80+2,MC_Black);
// On affiche les nouveaux:
Display_file_list(&Filelist, Position,offset);
Update_window_area(8-1,95-1,144+2,80+2);
if (setfilename)
{
// On récupère le nom du schmilblick à "accéder"
Get_selected_item(&Filelist, Position,offset,Selector_filename,Selector_filename_unicode,&Selected_type);
}
// On affiche le nouveau nom de fichier
Print_filename_in_fileselector();
// On affiche le nom du répertoire courant
Print_current_directory();
}
static void Reload_list_of_files(byte filter, T_Scroller_button * button)
{
Read_list_of_files(&Filelist, filter);
Sort_list_of_files(&Filelist);
//
// Check and fix the fileselector positions, because
// the directory content may have changed.
//
// Make the offset absolute
Selector->Offset += Selector->Position;
// Ensure it's within limits
if (Selector->Offset >= Filelist.Nb_elements)
{
Selector->Offset = Filelist.Nb_elements-1;
}
// Ensure the position doesn't show "too many files"
if (Selector->Position!=0 && Selector->Position>(Filelist.Nb_elements-10))
{
if (Filelist.Nb_elements<10)
{
Selector->Position=0;
}
else
{
Selector->Position=Filelist.Nb_elements-10;
}
}
// Restore the offset as relative to the position.
Selector->Offset -= Selector->Position;
Prepare_and_display_filelist(Selector->Position,Selector->Offset,button,1);
}
void Scroll_fileselector(T_Scroller_button * file_scroller)
{
char old_filename[MAX_PATH_CHARACTERS];
strcpy(old_filename,Selector_filename);
// On regarde si la liste a bougé
if (file_scroller->Position!=Selector->Position)
{
// Si c'est le cas, il faut mettre à jour la jauge
file_scroller->Position=Selector->Position;
Window_draw_slider(file_scroller);
}
// On récupére le nom du schmilblick à "accéder"
Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,Selector_filename_unicode,&Selected_type);
if (strcmp(old_filename,Selector_filename))
New_preview_is_needed=1;
// On affiche le nouveau nom de fichier
Print_filename_in_fileselector();
Display_cursor();
}
short Find_file_in_fileselector(T_Fileselector *list, const char * fname)
{
T_Fileselector_item * item;
short index;
short close_match = -1;
index=0;
for (item=list->First; item!=NULL; item=item->Next)
{
if (strcmp(item->Full_name,fname)==0)
return index; // exact match
if (strcasecmp(item->Full_name,fname)==0)
close_match=index;
index++;
}
return close_match;
}
/// Set the position and index of the file list according
/// to the selected index
/// @param index index of selected file
static void Highlight_file(short index)
{
if ((Filelist.Nb_elements<=10) || (index<5))
{
Selector->Position=0;
Selector->Offset=index;
}
else
{
if (index>=Filelist.Nb_elements-5)
{
Selector->Position=Filelist.Nb_elements-10;
Selector->Offset=index-Selector->Position;
}
else
{
Selector->Position=index-4;
Selector->Offset=4;
}
}
}
/// Find the item best matching the searched filename
///
/// used by quicksearch
/// @return -1 if not matching name found
static short Find_filename_match(const T_Fileselector *list, const word * fname)
{
short best_match;
T_Fileselector_item * current_item;
short item_number;
byte matching_letters=0;
byte counter;
best_match=-1;
item_number=0;
for (current_item=list->First; current_item!=NULL; current_item=current_item->Next)
{
if ( (!Config.Find_file_fast)
|| (Config.Find_file_fast==(current_item->Type+1)) )
{
// On compare et si c'est mieux, on stocke dans Meilleur_nom
if (current_item->Unicode_full_name != NULL)
{
for (counter = 0; fname[counter] != 0; counter++)
{
if (towlower(current_item->Unicode_full_name[counter]) != towlower(fname[counter]))
break;
}
}
else
{
for (counter=0; fname[counter] != 0; counter++)
{
if (tolower(current_item->Full_name[counter] != towlower(fname[counter])))
break;
}
}
if (counter>matching_letters)
{
matching_letters=counter;
best_match=item_number;
}
}
item_number++;
}
return best_match;
}
// Quicksearch system
#define MAX_QUICKSEARCH_LEN 50
/// Current quicksearch string
static word quicksearch_filename[MAX_QUICKSEARCH_LEN+1] = { 0 };
/// Reset the current quicksearch string
void Reset_quicksearch(void)
{
quicksearch_filename[0] = 0;
}
/// Select the item based on what the user type
static short Quicksearch(const T_Fileselector *selector)
{
word key;
size_t len;
short most_matching_item;
// Go to the filename which matches what is typed
len = Unicode_strlen(quicksearch_filename);
key = Key_UNICODE;
if (key == 0)
key = Key_ANSI;
if (key >= ' ' && len < MAX_QUICKSEARCH_LEN)
{
quicksearch_filename[len] = key;
quicksearch_filename[len+1] = 0;
most_matching_item = Find_filename_match(selector, quicksearch_filename);
if ( most_matching_item >= 0 )
return most_matching_item;
else
Reset_quicksearch();
}
return -1;
}
// Translated from Highlight_file
void Locate_list_item(T_List_button * list, short selected_item)
{
// Safety bounds
if (selected_item<0)
selected_item=0;
else if (selected_item>=list->Scroller->Nb_elements)
selected_item=list->Scroller->Nb_elements-1;
if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (selected_item<(list->Scroller->Nb_visibles/2)))
{
list->List_start=0;
list->Cursor_position=selected_item;
}
else
{
if (selected_item>=list->Scroller->Nb_elements-(list->Scroller->Nb_visibles/2))
{
list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles;
list->Cursor_position=selected_item-list->List_start;
}
else
{
list->List_start=selected_item-(list->Scroller->Nb_visibles/2-1);
list->Cursor_position=(list->Scroller->Nb_visibles/2-1);
}
}
}
int Quicksearch_list(T_List_button * list, T_Fileselector * selector)
{
// Try Quicksearch
short selected_item=Quicksearch(selector);
if (selected_item>=0 && selected_item!=list->Cursor_position+list->List_start)
{
Locate_list_item(list, selected_item);
Hide_cursor();
// Mise à jour du scroller
list->Scroller->Position=list->List_start;
Window_draw_slider(list->Scroller);
Window_redraw_list(list);
Display_cursor();
// Store the selected value as attribute2
Window_attribute2=list->List_start + list->Cursor_position;
// Return the control ID of the list.
return list->Number;
}
return 0;
}
byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context *context)
// load=1 => On affiche le menu du bouton LOAD
// load=0 => On affiche le menu du bouton SAVE
{
short clicked_button;
T_Scroller_button * file_scroller;
T_Dropdown_button * formats_dropdown;
T_Dropdown_button * bookmark_dropdown[4];
short temp;
unsigned int format;
int dummy=0; // Sert à appeler SDL_GetKeyState
byte save_or_load_image=0;
byte has_clicked_ok=0;// Indique si on a clické sur Load ou Save ou sur
//un bouton enclenchant Load ou Save juste après.
byte initial_back_color; // preview destroys it (how nice)
char save_filename[MAX_PATH_CHARACTERS];
word save_filename_unicode[MAX_PATH_CHARACTERS];
char initial_comment[COMMENT_SIZE+1];
short window_shortcut;
const char * directory_to_change_to = NULL;
Selector=settings;
Reset_quicksearch();
//if (Native_filesel(load) != 0); // TODO : handle this
if (context->Type == CONTEXT_MAIN_IMAGE)
window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE);
else
window_shortcut = load?SPECIAL_LOAD_BRUSH:SPECIAL_SAVE_BRUSH;
// Backup data that needs be restored on "cancel"
initial_back_color=Back_color;
strcpy(initial_comment,context->Comment);
if (load)
{
if (context->Type == CONTEXT_MAIN_IMAGE)
Open_window(310,200,"Load picture");
else if (context->Type == CONTEXT_PALETTE)
Open_window(310,200,"Load palette");
else
Open_window(310,200,"Load brush");
Window_set_normal_button(198,180,51,14,"Load",0,1,KEY_RETURN); // 1
}
else
{
if (context->Type == CONTEXT_MAIN_IMAGE)
Open_window(310,200,"Save picture");
else if (context->Type == CONTEXT_BRUSH)
Open_window(310,200,"Save brush");
else if (context->Type == CONTEXT_PALETTE)
Open_window(310,200,"Save palette");
else
assert(0);
Window_set_normal_button(198,180,51,14,"Save",0,1,KEY_RETURN); // 1
if (Selector->Format_filter<=FORMAT_ALL_FILES) // Correction du *.*
{
Selector->Format_filter=context->Format;
Selector->Position=0;
Selector->Offset=0;
}
if (Get_fileformat(Selector->Format_filter)->Save == NULL) // Correction d'un format insauvable
{
Selector->Format_filter=DEFAULT_FILEFORMAT;
Selector->Position=0;
Selector->Offset=0;
}
// Affichage du commentaire
if (Get_fileformat(Selector->Format_filter)->Comment)
Print_in_window(45,70,context->Comment,MC_Black,MC_Light);
}
Window_set_normal_button(253,180,51,14,"Cancel",0,1,KEY_ESC); // 2
Window_set_normal_button(7,180,51,14,"Delete",0,1,KEY_DELETE); // 3
// Frame autour des infos sur le fichier de dessin
Window_display_frame_in(6, 44,299, 37);
// Frame autour de la preview
Window_display_frame_in(181,93,124,84);
// Frame autour du fileselector
Window_display_frame_in(6,93,148,84);
// Fileselector
Window_set_special_button(9,95,144,80,0); // 4
// Scroller du fileselector
file_scroller = Window_set_scroller_button(160,94,82,1,10,0); // 5
// Dropdown pour les formats de fichier
formats_dropdown=
Window_set_dropdown_button(68,28,52,11,0,
Get_fileformat(Selector->Format_filter)->Label,
1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6
for (format=0; format < Nb_known_formats(); format++)
{
if (File_formats[format].Identifier > FORMAT_ALL_FILES)
{
if (load && !File_formats[format].Load) //filter out formats without Load function
continue;
if (!load && !File_formats[format].Save) // filter out formats without Save function
continue;
}
if (!load && ((context->Type == CONTEXT_PALETTE) != File_formats[format].Palette_only))
continue; // Only Palette only format when SAVING palette and not Palette only when saving image
Window_dropdown_add_item(formats_dropdown,File_formats[format].Identifier,File_formats[format].Label);
}
Print_in_window(70,18,"Format",MC_Dark,MC_Light);
// Texte de commentaire des dessins
Print_in_window(9,70,"Txt:",MC_Dark,MC_Light);
Window_set_input_button(43,68,COMMENT_SIZE); // 7
// Saisie du nom de fichier
Window_set_input_button(80,46,27); // 8
Print_in_window(9,47,"Filename",MC_Dark,MC_Light);
Print_in_window(9,59,"Image:",MC_Dark,MC_Light);
Print_in_window(228,59,"(",MC_Dark,MC_Light);
Print_in_window(292,59,")",MC_Dark,MC_Light);
// Selecteur de Lecteur / Volume
Window_set_normal_button(7,18,53,23,"",0,1,KEY_NONE); // 9
Print_in_window(10,22,"Select",MC_Black,MC_Light);
Print_in_window(14,30,"drive",MC_Black,MC_Light);
// Bookmarks
for (temp=0;temp<NB_BOOKMARKS;temp++)
{
bookmark_dropdown[temp]=
Window_set_dropdown_button(127+(88+1)*(temp%2),18+(temp/2)*12,88,11,56,"",0,0,1,RIGHT_SIDE,0); // 10-13
Window_display_icon_sprite(bookmark_dropdown[temp]->Pos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR);
Display_bookmark(bookmark_dropdown[temp],temp);
}
Change_directory(context->File_directory);
Get_current_directory(Selector->Directory, Selector->Directory_unicode, MAX_PATH_CHARACTERS);
// Affichage des premiers fichiers visibles:
Reload_list_of_files(Selector->Format_filter,file_scroller);
if (!load)
{
short pos = Find_file_in_fileselector(&Filelist, context->File_name);
Highlight_file((pos >= 0) ? pos : 0);
Selected_type = (pos >= 0) ? FSOBJECT_FILE : FSOBJECT_DIR;
Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller,0);
// On initialise le nom de fichier à celui en cours et non pas celui sous
// la barre de sélection
strcpy(Selector_filename,context->File_name);
Unicode_strlcpy(Selector_filename_unicode, context->File_name_unicode, 256);
// On affiche le nouveau nom de fichier
Print_filename_in_fileselector();
}
New_preview_is_needed=1;
Update_window_area(0,0,Window_width, Window_height);
Display_cursor();
do
{
clicked_button=Window_clicked_button();
switch (clicked_button)
{
case -1 :
case 0 :
break;
case 1 : // Load ou Save
if(load) // Determine the type
Selected_type = (File_exists(Selector_filename) && !Directory_exists(Selector_filename)) ? FSOBJECT_FILE : FSOBJECT_DIR;
else
Selected_type = Directory_exists(Selector_filename) ? FSOBJECT_DIR : FSOBJECT_FILE;
has_clicked_ok=1;
break;
case 2 : // Cancel
break;
case 3 : // Delete
if (Filelist.Nb_elements && (*Selector_filename!='.') && Selected_type != FSOBJECT_DRIVE)
{
char * message;
Hide_cursor();
// On affiche une demande de confirmation
if (Selector->Position+Selector->Offset>=Filelist.Nb_directories)
{
message="Delete file ?";
}
else
{
message="Remove directory ?";
}
if (Confirmation_box(message))
{
// Si c'est un fichier
if (Selector->Position+Selector->Offset>=Filelist.Nb_directories)
// On efface le fichier (si on peut)
temp=(!Remove_path(Selector_filename));
else // Si c'est un repertoire
// On efface le repertoire (si on peut)
temp=(!Remove_directory(Selector_filename));
if (temp) // temp indique si l'effacement s'est bien passé
{
// On remonte si c'était le dernier élément de la liste
if (Selector->Position+Selector->Offset==Filelist.Nb_elements-1)
{
if (Selector->Position)
Selector->Position--;
else
if (Selector->Offset)
Selector->Offset--;
}
else // Si ce n'était pas le dernier, il faut faire gaffe à ce
{ // que ses copains d'en dessous ne remontent pas trop.
if ( (Selector->Position)
&& (Selector->Position+10==Filelist.Nb_elements) )
{
Selector->Position--;
Selector->Offset++;
}
}
// On relit les informations
Reload_list_of_files(Selector->Format_filter,file_scroller);
// On demande la preview du nouveau fichier sur lequel on se trouve
New_preview_is_needed=1;
}
else
Error(0);
}
}
break;
case 4 : // Zone d'affichage de la liste de fichiers
Hide_cursor();
temp=Compute_click_offset_in_fileselector();
if (temp>=0)
{
if (temp!=Selector->Offset)
{
// first click on an item.
// update offset
Selector->Offset=temp;
// get item name and details
Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,Selector_filename_unicode,&Selected_type);
// display the new filename
Print_filename_in_fileselector();
// and update list
Display_file_list(&Filelist, Selector->Position,Selector->Offset);
// A new file is selected so a new preview is needed
New_preview_is_needed=1;
Reset_quicksearch();
}
else
{
// This is the second click on the same item => Double click
// En sauvegarde, si on a double-clické sur un répertoire, il
// faut mettre le nom de fichier au nom du répertoire. Sinon, dans
// certains cas, on risque de sauvegarder avec le nom du fichier
// actuel au lieu de changer de répertoire.
if (Selector->Position+Selector->Offset < Filelist.Nb_directories)
{ // clicked on a directory
// retrieve again the item name
Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,Selector_filename_unicode,&Selected_type);
}
has_clicked_ok=1;
New_preview_is_needed=1;
Reset_quicksearch();
}
}
Display_cursor();
Wait_end_of_click();
break;
case 5 : // Scroller de fichiers
Hide_cursor();
Selector->Position=Window_attribute2;
// On récupére le nom du schmilblick à "accéder"
Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,Selector_filename_unicode,&Selected_type);
// On affiche le nouveau nom de fichier
Print_filename_in_fileselector();
// On affiche à nouveau la liste
Display_file_list(&Filelist, Selector->Position,Selector->Offset);
Display_cursor();
New_preview_is_needed=1;
Reset_quicksearch();
break;
case 6 : // File Format dropdown
// Refresh fileselector according to new filter
if (Selector->Format_filter != Window_attribute2)
{
int pos_last_dot;
char* savename = NULL;
word Selector_filename_unicode_save[256];
GFX2_Log(GFX2_DEBUG, "fileselector format changed from %d to %d\n", (int)Selector->Format_filter, (int)Window_attribute2);
Selector->Format_filter = Window_attribute2;
if (!load)
{
// In "save" box, if current name is a (possible) filename
// with extension, set it to new format's extension
pos_last_dot = Position_last_dot(Selector_filename);
if (Get_fileformat(Selector->Format_filter)->Default_extension[0] != '\0' &&
pos_last_dot!=-1 &&
Selector_filename[pos_last_dot+1]!='\0')
{
GFX2_Log(GFX2_DEBUG, "extension %s => %s\n", Selector_filename + pos_last_dot + 1, Get_fileformat(Selector->Format_filter)->Default_extension);
strcpy(Selector_filename + pos_last_dot + 1,
Get_fileformat(Selector->Format_filter)->Default_extension);
pos_last_dot = Position_last_dot_unicode(Selector_filename_unicode);
if (pos_last_dot != -1)
Unicode_char_strlcpy(Selector_filename_unicode + pos_last_dot + 1,
Get_fileformat(Selector->Format_filter)->Default_extension, 256 - pos_last_dot - 1);
}
}
savename = (char *)strdup(Selector_filename);
memcpy(Selector_filename_unicode_save, Selector_filename_unicode, sizeof(Selector_filename_unicode_save));
// By default, position list at the beginning
Selector->Position = 0;
Selector->Offset = 0;
// Print the first visible files
Hide_cursor();
Reload_list_of_files(Selector->Format_filter, file_scroller);
New_preview_is_needed = 1;
Reset_quicksearch();
if (savename != NULL)
{
// attempt to find the file name in new list
short pos=Find_file_in_fileselector(&Filelist, savename);
if (pos >= 0)
{
Highlight_file(pos);
Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller,load);
}
// If the file is (still present) or it's a name with new
// extension, set it as the proposed file name.
if (pos >= 0 || !load)
{
strcpy(Selector_filename, savename);
memcpy(Selector_filename_unicode, Selector_filename_unicode_save, sizeof(Selector_filename_unicode_save));
}
free(savename);
}
Print_filename_in_fileselector();
Display_cursor();
}
break;
case 7 : // Saisie d'un commentaire pour la sauvegarde
if ( (!load) && (Get_fileformat(Selector->Format_filter)->Comment) )
{
Readline(45, 70, context->Comment, 32, INPUT_TYPE_STRING);
Display_cursor();
}
break;
case 8 : // Saisie du nom de fichier
{
char filename_ansi[256];
word filename_unicode[256];
// Save the filename
strcpy(save_filename, Selector_filename);
Unicode_strlcpy(save_filename_unicode, Selector_filename_unicode, MAX_PATH_CHARACTERS);
// Check if the selected entry is a drive/directory :
// in, this case, clear the filename
if (Filelist.Nb_elements>0)
{
T_Fileselector_item * current_item;
current_item = Get_item_by_index(&Filelist, Selector->Position + Selector->Offset);
if (current_item->Type != FSOBJECT_FILE && !FILENAME_COMPARE(current_item->Full_name,Selector_filename))
{
// current name is a highlighted directory
Selector_filename[0]='\0';
Selector_filename_unicode[0]=0;
}
}
strncpy(filename_ansi, Selector_filename, sizeof(filename_ansi));
if (Selector_filename_unicode[0] == 0 && strlen(Selector_filename) > 0)
Unicode_char_strlcpy(filename_unicode, Selector_filename, sizeof(filename_unicode)/sizeof(word));
else
Unicode_strlcpy(filename_unicode, Selector_filename_unicode, sizeof(filename_unicode)/sizeof(word));
#ifdef ENABLE_FILENAMES_ICONV
{ /* convert from UTF8 to ANSI */
char * input = (char *)Selector_filename;
size_t inbytesleft = strlen(input);
char * output = filename_ansi;
size_t outbytesleft = sizeof(filename_ansi)-1;
if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0)
*output = '\0';
}
#endif /* ENABLE_FILENAMES_ICONV */
#if defined(WIN32) || defined(ENABLE_FILENAMES_ICONV)
if (Readline_ex_unicode(82,48,filename_ansi,filename_unicode,27,sizeof(filename_ansi)-1,INPUT_TYPE_FILENAME,0))
#else
if (Readline_ex_unicode(82,48,filename_ansi,NULL,27,sizeof(filename_ansi)-1,INPUT_TYPE_FILENAME,0))
#endif
{
#if defined(WIN32)
WCHAR temp_str[MAX_PATH_CHARACTERS];
if (GetShortPathNameW((WCHAR *)filename_unicode, temp_str, MAX_PATH_CHARACTERS) == 0)
{
// generate a temporary ansi name
int i;
for (i = 0; i < MAX_PATH_CHARACTERS - 1 && filename_unicode[i] != 0; i++)
{
filename_ansi[i] = (filename_unicode[i] < 256) ? (byte)filename_unicode[i] : '_';
}
filename_ansi[i] = '\0';
}
else
{
int i;
for (i = 0; i < MAX_PATH_CHARACTERS - 1 && temp_str[i] != 0; i++)
filename_ansi[i] = temp_str[i];
filename_ansi[i] = '\0';
}
#elif defined(ENABLE_FILENAMES_ICONV)
/* convert back from UTF16 to UTF8 */
char * input = (char *)filename_unicode;
size_t inbytesleft = 2 * Unicode_strlen(filename_unicode);
char * output = Selector_filename;
size_t outbytesleft = sizeof(Selector_filename)-1;
if(cd_utf16_inv != (iconv_t)-1 && (ssize_t)iconv(cd_utf16_inv, &input, &inbytesleft, &output, &outbytesleft) >= 0)
*output = '\0';
else
#endif
strncpy(Selector_filename, filename_ansi, sizeof(Selector_filename));
#if defined(WIN32) || defined(ENABLE_FILENAMES_ICONV)
Unicode_strlcpy(Selector_filename_unicode, filename_unicode, sizeof(Selector_filename_unicode)/sizeof(word));
#endif
// On regarde s'il faut rajouter une extension. C'est-à-dire s'il
// n'y a pas de '.' dans le nom du fichier.
for(temp=0,dummy=0; ((Selector_filename[temp]) && (!dummy)); temp++)
if (Selector_filename[temp]=='.')
dummy=1;
if (!dummy)
{
if(!Directory_exists(Selector_filename))
{
const char * ext = Get_fileformat(Selector->Format_filter)->Default_extension;
// put default extension
// (but maybe we should browse through all available ones until we find
// something suitable ?)
if (ext == NULL)
ext = "pkm";
strcat(Selector_filename, ".");
strcat(Selector_filename, ext);
Unicode_char_strlcat(Selector_filename_unicode, ".", sizeof(Selector_filename_unicode)/sizeof(word));
Unicode_char_strlcat(Selector_filename_unicode, ext, sizeof(Selector_filename_unicode)/sizeof(word));
}
}
if(load) // Determine the type
Selected_type = (File_exists(Selector_filename) && !Directory_exists(Selector_filename)) ? FSOBJECT_FILE : FSOBJECT_DIR;
else
Selected_type = Directory_exists(Selector_filename) ? FSOBJECT_DIR : FSOBJECT_FILE;
// Now load immediately, but only if the user exited readline by pressing ENTER
if (Mouse_K == 0) has_clicked_ok = 1;
}
else
{
// Restore the old filename
strcpy(Selector_filename, save_filename);
Unicode_strlcpy(Selector_filename_unicode, save_filename_unicode, sizeof(Selector_filename_unicode)/sizeof(word));
}
Print_filename_in_fileselector();
Display_cursor();
break;
}
case 9 : // Volume Select
Hide_cursor();
// Comme on tombe sur un disque qu'on connait pas, on se place en
// début de liste:
Selector->Position=0;
Selector->Offset=0;
// Affichage des premiers fichiers visibles:
Read_list_of_drives(&Filelist,19);
Sort_list_of_files(&Filelist);
Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller,0);
Display_cursor();
New_preview_is_needed=1;
Reset_quicksearch();
break;
default:
if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS)
{
// Bookmark
char * directory_name;
switch(Window_attribute2)
{
case -1: // bouton lui-même: aller au répertoire mémorisé
if (Config.Bookmark_directory[clicked_button-10])
{
GFX2_Log(GFX2_DEBUG,"Go to bookmark %s\n", Config.Bookmark_directory[clicked_button-10]);
// backup the currently selected filename
strncpy(save_filename, Selector_filename, sizeof(save_filename));
// simulate a click on the bookmarked directory
directory_to_change_to = Config.Bookmark_directory[clicked_button-10];
Reset_quicksearch();
}
break;
case 0: // Set
free(Config.Bookmark_directory[clicked_button-10]);
Config.Bookmark_directory[clicked_button-10] = NULL;
Config.Bookmark_label[clicked_button-10][0]='\0';
temp=strlen(Selector->Directory);
Config.Bookmark_directory[clicked_button-10]=malloc(temp+1);
strcpy(Config.Bookmark_directory[clicked_button-10],Selector->Directory);
directory_name=Find_last_separator(Selector->Directory);
if (directory_name && directory_name[1]!='\0')
directory_name++;
else
directory_name=Selector->Directory;
temp=strlen(directory_name);
strncpy(Config.Bookmark_label[clicked_button-10],directory_name,8);
if (temp>8)
{
Config.Bookmark_label[clicked_button-10][7]=ELLIPSIS_CHARACTER;
Config.Bookmark_label[clicked_button-10][8]='\0';
}
Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10);
break;
case 1: // Rename
if (Config.Bookmark_directory[clicked_button-10])
{
// On enlève les "..." avant l'édition
char bookmark_label[8+1];
strcpy(bookmark_label, Config.Bookmark_label[clicked_button-10]);
if (bookmark_label[7]==ELLIPSIS_CHARACTER)
bookmark_label[7]='\0';
if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,INPUT_TYPE_STRING,0))
strcpy(Config.Bookmark_label[clicked_button-10],bookmark_label);
Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10);
Display_cursor();
}
break;
case 2: // Clear
if (Config.Bookmark_directory[clicked_button-10] && Confirmation_box("Erase bookmark ?"))
{
free(Config.Bookmark_directory[clicked_button-10]);
Config.Bookmark_directory[clicked_button-10]=NULL;
Config.Bookmark_label[clicked_button-10][0]='\0';
Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10);
}
break;
}
}
break;
}
switch (Key)
{
case KEY_UNKNOWN : break;
case KEY_DOWN : // Bas
Reset_quicksearch();
Hide_cursor();
Selector_scroll_down(&Selector->Position,&Selector->Offset);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_UP : // Haut
Reset_quicksearch();
Hide_cursor();
Selector_scroll_up(&Selector->Position,&Selector->Offset);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_PAGEDOWN : // PageDown
Reset_quicksearch();
Hide_cursor();
Selector_page_down(&Selector->Position,&Selector->Offset,9);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_PAGEUP : // PageUp
Reset_quicksearch();
Hide_cursor();
Selector_page_up(&Selector->Position,&Selector->Offset,9);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_END : // End
Reset_quicksearch();
Hide_cursor();
Selector_end(&Selector->Position,&Selector->Offset);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_HOME : // Home
Reset_quicksearch();
Hide_cursor();
Selector_home(&Selector->Position,&Selector->Offset);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_MOUSEWHEELDOWN :
Reset_quicksearch();
Hide_cursor();
Selector_page_down(&Selector->Position,&Selector->Offset,3);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_MOUSEWHEELUP :
Reset_quicksearch();
Hide_cursor();
Selector_page_up(&Selector->Position,&Selector->Offset,3);
Scroll_fileselector(file_scroller);
Key=0;
break;
case KEY_BACKSPACE : // Backspace
Reset_quicksearch();
// Si le choix ".." est bien en tête des propositions...
if (Filelist.Nb_elements && !strcmp(Filelist.First->Full_name,PARENT_DIR))
{
// On va dans le répertoire parent.
strcpy(Selector_filename,PARENT_DIR);
Selector_filename_unicode[0] = 0;
Selected_type=FSOBJECT_DIR;
has_clicked_ok=1;
}
Key=0;
break;
default:
if (clicked_button<=0)
{
short selected_item;
if (Is_shortcut(Key,0x100+BUTTON_HELP))
{
Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL);
break;
}
if (Is_shortcut(Key,window_shortcut))
{
clicked_button=2;
break;
}
selected_item=Quicksearch(&Filelist);
if (selected_item>=0)
{
temp=Selector->Position+Selector->Offset;
Hide_cursor();
Highlight_file(selected_item);
Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller,1);
Display_cursor();
if (temp!=Selector->Position+Selector->Offset)
New_preview_is_needed=1;
}
// Key=0; ?
}
else
Reset_quicksearch();
}
if (has_clicked_ok || (directory_to_change_to != NULL))
{
// Si c'est un répertoire, on annule "has_clicked_ok" et on passe
// dedans.
if (Selected_type!=FSOBJECT_FILE || (directory_to_change_to != NULL))
{
Hide_cursor();
has_clicked_ok=0;
if (directory_to_change_to == NULL)
directory_to_change_to = Selector_filename;
// We must enter the directory
if (Change_directory(directory_to_change_to) == 0)
{
short pos;
char previous_directory[MAX_PATH_CHARACTERS]; // Répertoire d'où l'on vient après un CHDIR
#if defined (__MINT__)
static char path[1024]={0};
char currentDrive='A';
#endif
// save the previous current directory
if (strcmp(directory_to_change_to,PARENT_DIR) != 0)
{
strcpy(previous_directory,PARENT_DIR);
}
else
{
Extract_filename(previous_directory, Selector->Directory);
}
Get_current_directory(Selector->Directory, Selector->Directory_unicode, MAX_PATH_CHARACTERS);
// read the new directory
Read_list_of_files(&Filelist, Selector->Format_filter);
Sort_list_of_files(&Filelist);
// Set the fileselector bar on the directory we're coming from
pos = Find_file_in_fileselector(&Filelist, previous_directory);
Highlight_file((pos >= 0) ? pos : 0);
// display the 1st visible files
Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller,0);
Display_cursor();
New_preview_is_needed=1;
// New directory, so we need to reset the quicksearch
Reset_quicksearch();
}
else
{
char warn_msg[MAX_PATH_CHARACTERS];
Display_cursor();
snprintf(warn_msg, sizeof(warn_msg), "cannot chdir to \"%s\" !", directory_to_change_to);
Warning(warn_msg);
// restore Selector_filename
strncpy(Selector_filename, save_filename, sizeof(Selector_filename));
Error(0);
}
directory_to_change_to = NULL;
}
else // Sinon on essaye de charger ou sauver le fichier
{
strcpy(context->File_directory,Selector->Directory);
context->Format = Selector->Format_filter;
save_or_load_image=1;
}
}
// Gestion du chrono et des previews
if (New_preview_is_needed)
{
// On efface les infos de la preview précédente s'il y en a une
// d'affichée
if (Timer_state==2)
{
Hide_cursor();
// On efface le commentaire précédent
Window_rectangle(45,70,32*8,8,MC_Light);
// On nettoie la zone où va s'afficher la preview:
Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light);
// On efface les dimensions de l'image
Window_rectangle(101,59,120,8,MC_Light);
// On efface la taille du fichier
Window_rectangle(236,59,56,8,MC_Light);
// On efface le format du fichier
Window_rectangle(59,59,5*8,8,MC_Light);
// Affichage du commentaire
if ( (!load) && (Get_fileformat(Selector->Format_filter)->Comment) )
{
Print_in_window(45,70,context->Comment,MC_Black,MC_Light);
}
Display_cursor();
// Un update pour couvrir les 4 zones: 3 libellés plus le commentaire
Update_window_area(45,48,256,30);
// Zone de preview
Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT);
}
New_preview_is_needed=0;
Timer_state=0; // State du chrono = Attente d'un Xème de seconde
// On lit le temps de départ du chrono
Init_chrono(Config.Timer_delay);
}
if (!Timer_state) // Prendre une nouvelle mesure du chrono et regarder
Check_timer(); // s'il ne faut pas afficher la preview
if (Timer_state==1) // Il faut afficher la preview
{
if ( (Selector->Position+Selector->Offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) )
{
T_IO_Context preview_context;
Init_context_preview(&preview_context, Selector_filename, Selector->Directory);
preview_context.Format = Selector->Format_filter;
preview_context.File_name_unicode = Selector_filename_unicode;
Hide_cursor();
if (context->Type == CONTEXT_PALETTE)
preview_context.Type = CONTEXT_PREVIEW_PALETTE;
Load_image(&preview_context);
Destroy_context(&preview_context);
Update_window_area(0,0,Window_width,Window_height);
Display_cursor();
}
Timer_state=2; // On arrête le chrono
}
}
while ( (!has_clicked_ok) && (clicked_button!=2) );
if (has_clicked_ok)
{
strcpy(context->File_name, Selector_filename);
if (context->File_name_unicode)
Unicode_strlcpy(context->File_name_unicode, Selector_filename_unicode, MAX_PATH_CHARACTERS);
strcpy(context->File_directory, Selector->Directory);
if (!load)
context->Format = Selector->Format_filter;
}
else
{
// Data to restore
strcpy(context->Comment, initial_comment);
}
// On restaure les données de l'image qui ont certainement été modifiées
// par la preview.
Back_color=initial_back_color;
if (Windows_open <= 1)
{
// Restore Main.palette only when we are not going back to another window
// (we let the other window take care of its palette and remapping)
// This test was added for Load/Save dialog called from the Palette window
Set_palette(Main.palette);
Compute_optimal_menu_colors(Main.palette);
}
temp=(Window_pos_Y+(Window_height*Menu_factor_Y)<Menu_Y_before_window);
Close_window();
if (temp && Windows_open < 1)
Display_menu();
Unselect_button((load)?BUTTON_LOAD:BUTTON_SAVE);
Display_cursor();
Free_fileselector_list(&Filelist);
return save_or_load_image;
}