2008-12-18 19:21:30 +00:00
|
|
|
/**
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2007 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* global includes */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#else
|
|
|
|
#include <io.h>
|
|
|
|
#include <direct.h>
|
|
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
#include "BLI_storage_types.h"
|
2009-01-18 18:24:11 +00:00
|
|
|
#include "BLI_threads.h"
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include "BLI_winstuff.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BLO_readfile.h"
|
|
|
|
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "DNA_ipo_types.h"
|
|
|
|
#include "DNA_ID.h"
|
|
|
|
#include "DNA_object_types.h"
|
2009-01-18 19:12:13 +00:00
|
|
|
#include "DNA_listBase.h"
|
2008-12-18 19:21:30 +00:00
|
|
|
#include "DNA_lamp_types.h"
|
|
|
|
#include "DNA_material_types.h"
|
|
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "DNA_world_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_userdef_types.h"
|
|
|
|
|
2009-01-06 14:42:54 +00:00
|
|
|
#include "ED_datafiles.h"
|
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "IMB_thumbs.h"
|
|
|
|
|
|
|
|
#include "PIL_time.h"
|
|
|
|
|
2009-04-10 16:30:28 +00:00
|
|
|
#include "UI_interface.h"
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
#include "filelist.h"
|
|
|
|
|
|
|
|
/* Elubie: VERY, really very ugly and evil! Remove asap!!! */
|
|
|
|
/* for state of file */
|
|
|
|
#define ACTIVE 2
|
|
|
|
|
|
|
|
/* max length of library group name within filesel */
|
|
|
|
#define GROUP_MAX 32
|
|
|
|
|
2009-01-18 18:24:11 +00:00
|
|
|
static void *exec_loadimages(void *list_v);
|
|
|
|
|
|
|
|
struct FileList;
|
|
|
|
|
|
|
|
typedef struct FileImage {
|
|
|
|
struct FileImage *next, *prev;
|
|
|
|
int index;
|
|
|
|
short lock;
|
|
|
|
short done;
|
|
|
|
struct FileList* filelist;
|
|
|
|
} FileImage;
|
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
typedef struct FileList
|
|
|
|
{
|
|
|
|
struct direntry *filelist;
|
|
|
|
int *fidx;
|
|
|
|
|
|
|
|
int numfiles;
|
|
|
|
int numfiltered;
|
|
|
|
char dir[FILE_MAX];
|
|
|
|
int has_func;
|
|
|
|
short prv_w;
|
|
|
|
short prv_h;
|
|
|
|
short hide_dot;
|
|
|
|
unsigned int filter;
|
2009-01-18 18:24:11 +00:00
|
|
|
short changed;
|
|
|
|
ListBase loadimages;
|
|
|
|
ListBase threads;
|
2008-12-18 19:21:30 +00:00
|
|
|
} FileList;
|
|
|
|
|
2009-07-07 07:25:44 +00:00
|
|
|
typedef struct FolderList
|
|
|
|
{
|
|
|
|
struct FolderList *next, *prev;
|
|
|
|
char *foldername;
|
|
|
|
} FolderList;
|
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
#define SPECIAL_IMG_SIZE 48
|
|
|
|
#define SPECIAL_IMG_ROWS 4
|
|
|
|
#define SPECIAL_IMG_COLS 4
|
|
|
|
|
|
|
|
#define SPECIAL_IMG_FOLDER 0
|
|
|
|
#define SPECIAL_IMG_PARENT 1
|
|
|
|
#define SPECIAL_IMG_REFRESH 2
|
|
|
|
#define SPECIAL_IMG_BLENDFILE 3
|
|
|
|
#define SPECIAL_IMG_SOUNDFILE 4
|
|
|
|
#define SPECIAL_IMG_MOVIEFILE 5
|
|
|
|
#define SPECIAL_IMG_PYTHONFILE 6
|
|
|
|
#define SPECIAL_IMG_TEXTFILE 7
|
|
|
|
#define SPECIAL_IMG_FONTFILE 8
|
|
|
|
#define SPECIAL_IMG_UNKNOWNFILE 9
|
2009-03-11 23:22:07 +00:00
|
|
|
#define SPECIAL_IMG_LOADING 10
|
|
|
|
#define SPECIAL_IMG_MAX SPECIAL_IMG_LOADING + 1
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX];
|
|
|
|
|
|
|
|
|
|
|
|
/* ******************* SORT ******************* */
|
|
|
|
|
|
|
|
static int compare_name(const void *a1, const void *a2)
|
|
|
|
{
|
|
|
|
const struct direntry *entry1=a1, *entry2=a2;
|
|
|
|
|
|
|
|
/* type is is equal to stat.st_mode */
|
|
|
|
|
|
|
|
if (S_ISDIR(entry1->type)){
|
|
|
|
if (S_ISDIR(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISDIR(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if (S_ISREG(entry1->type)){
|
|
|
|
if (S_ISREG(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISREG(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
|
|
|
|
if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
|
|
|
|
|
|
|
|
/* make sure "." and ".." are always first */
|
|
|
|
if( strcmp(entry1->relname, ".")==0 ) return (-1);
|
|
|
|
if( strcmp(entry2->relname, ".")==0 ) return (1);
|
|
|
|
if( strcmp(entry1->relname, "..")==0 ) return (-1);
|
2009-03-11 23:22:07 +00:00
|
|
|
if( strcmp(entry2->relname, "..")==0 ) return (1);
|
2008-12-18 19:21:30 +00:00
|
|
|
|
2009-06-08 20:08:19 +00:00
|
|
|
return (BLI_natstrcmp(entry1->relname,entry2->relname));
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_date(const void *a1, const void *a2)
|
|
|
|
{
|
|
|
|
const struct direntry *entry1=a1, *entry2=a2;
|
|
|
|
|
|
|
|
/* type is equal to stat.st_mode */
|
|
|
|
|
|
|
|
if (S_ISDIR(entry1->type)){
|
|
|
|
if (S_ISDIR(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISDIR(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if (S_ISREG(entry1->type)){
|
|
|
|
if (S_ISREG(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISREG(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
|
|
|
|
if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
|
|
|
|
|
|
|
|
/* make sure "." and ".." are always first */
|
|
|
|
if( strcmp(entry1->relname, ".")==0 ) return (-1);
|
|
|
|
if( strcmp(entry2->relname, ".")==0 ) return (1);
|
|
|
|
if( strcmp(entry1->relname, "..")==0 ) return (-1);
|
2009-03-11 23:22:07 +00:00
|
|
|
if( strcmp(entry2->relname, "..")==0 ) return (1);
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
|
|
|
|
if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
|
|
|
|
|
2009-06-08 20:08:19 +00:00
|
|
|
else return BLI_natstrcmp(entry1->relname,entry2->relname);
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_size(const void *a1, const void *a2)
|
|
|
|
{
|
|
|
|
const struct direntry *entry1=a1, *entry2=a2;
|
|
|
|
|
|
|
|
/* type is equal to stat.st_mode */
|
|
|
|
|
|
|
|
if (S_ISDIR(entry1->type)){
|
|
|
|
if (S_ISDIR(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISDIR(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if (S_ISREG(entry1->type)){
|
|
|
|
if (S_ISREG(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISREG(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
|
|
|
|
if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
|
|
|
|
|
|
|
|
/* make sure "." and ".." are always first */
|
|
|
|
if( strcmp(entry1->relname, ".")==0 ) return (-1);
|
|
|
|
if( strcmp(entry2->relname, ".")==0 ) return (1);
|
|
|
|
if( strcmp(entry1->relname, "..")==0 ) return (-1);
|
2009-03-11 23:22:07 +00:00
|
|
|
if( strcmp(entry2->relname, "..")==0 ) return (1);
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
if ( entry1->s.st_size < entry2->s.st_size) return 1;
|
|
|
|
if ( entry1->s.st_size > entry2->s.st_size) return -1;
|
2009-06-08 20:08:19 +00:00
|
|
|
else return BLI_natstrcmp(entry1->relname,entry2->relname);
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_extension(const void *a1, const void *a2) {
|
|
|
|
const struct direntry *entry1=a1, *entry2=a2;
|
|
|
|
char *sufix1, *sufix2;
|
|
|
|
char *nil="";
|
|
|
|
|
|
|
|
if (!(sufix1= strstr (entry1->relname, ".blend.gz")))
|
|
|
|
sufix1= strrchr (entry1->relname, '.');
|
|
|
|
if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
|
|
|
|
sufix2= strrchr (entry2->relname, '.');
|
|
|
|
if (!sufix1) sufix1= nil;
|
|
|
|
if (!sufix2) sufix2= nil;
|
|
|
|
|
|
|
|
/* type is is equal to stat.st_mode */
|
|
|
|
|
|
|
|
if (S_ISDIR(entry1->type)){
|
|
|
|
if (S_ISDIR(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISDIR(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if (S_ISREG(entry1->type)){
|
|
|
|
if (S_ISREG(entry2->type)==0) return (-1);
|
|
|
|
} else{
|
|
|
|
if (S_ISREG(entry2->type)) return (1);
|
|
|
|
}
|
|
|
|
if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
|
|
|
|
if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
|
|
|
|
|
|
|
|
/* make sure "." and ".." are always first */
|
|
|
|
if( strcmp(entry1->relname, ".")==0 ) return (-1);
|
|
|
|
if( strcmp(entry2->relname, ".")==0 ) return (1);
|
|
|
|
if( strcmp(entry1->relname, "..")==0 ) return (-1);
|
2009-03-11 23:22:07 +00:00
|
|
|
if( strcmp(entry2->relname, "..")==0 ) return (1);
|
2008-12-18 19:21:30 +00:00
|
|
|
|
|
|
|
return (BLI_strcasecmp(sufix1, sufix2));
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_filter(FileList* filelist)
|
|
|
|
{
|
|
|
|
int num_filtered = 0;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
if (!filelist->filelist)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!filelist->filter) {
|
|
|
|
if (filelist->fidx) {
|
|
|
|
MEM_freeN(filelist->fidx);
|
|
|
|
filelist->fidx = NULL;
|
|
|
|
}
|
|
|
|
filelist->fidx = (int *)MEM_callocN(filelist->numfiles*sizeof(int), "filteridx");
|
|
|
|
for (i = 0; i < filelist->numfiles; ++i) {
|
|
|
|
filelist->fidx[i] = i;
|
|
|
|
}
|
|
|
|
filelist->numfiltered = filelist->numfiles;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// How many files are left after filter ?
|
|
|
|
for (i = 0; i < filelist->numfiles; ++i) {
|
|
|
|
if (filelist->filelist[i].flags & filelist->filter) {
|
|
|
|
num_filtered++;
|
|
|
|
}
|
|
|
|
else if (filelist->filelist[i].type & S_IFDIR) {
|
|
|
|
if (filelist->filter & FOLDERFILE) {
|
|
|
|
num_filtered++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filelist->fidx) {
|
|
|
|
MEM_freeN(filelist->fidx);
|
|
|
|
filelist->fidx = NULL;
|
|
|
|
}
|
|
|
|
filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx");
|
|
|
|
filelist->numfiltered = num_filtered;
|
|
|
|
|
|
|
|
for (i = 0, j=0; i < filelist->numfiles; ++i) {
|
|
|
|
if (filelist->filelist[i].flags & filelist->filter) {
|
|
|
|
filelist->fidx[j++] = i;
|
|
|
|
}
|
|
|
|
else if (filelist->filelist[i].type & S_IFDIR) {
|
|
|
|
if (filelist->filter & FOLDERFILE) {
|
|
|
|
filelist->fidx[j++] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_init_icons()
|
|
|
|
{
|
|
|
|
short x, y, k;
|
|
|
|
ImBuf *bbuf;
|
|
|
|
ImBuf *ibuf;
|
|
|
|
bbuf = IMB_ibImageFromMemory((int *)datatoc_prvicons, datatoc_prvicons_size, IB_rect);
|
|
|
|
if (bbuf) {
|
|
|
|
for (y=0; y<SPECIAL_IMG_ROWS; y++) {
|
|
|
|
for (x=0; x<SPECIAL_IMG_COLS; x++) {
|
|
|
|
int tile = SPECIAL_IMG_COLS*y + x;
|
|
|
|
if (tile < SPECIAL_IMG_MAX) {
|
|
|
|
ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect, 0);
|
|
|
|
for (k=0; k<SPECIAL_IMG_SIZE; k++) {
|
|
|
|
memcpy(&ibuf->rect[k*SPECIAL_IMG_SIZE], &bbuf->rect[(k+y*SPECIAL_IMG_SIZE)*SPECIAL_IMG_SIZE*SPECIAL_IMG_COLS+x*SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE*sizeof(int));
|
|
|
|
}
|
|
|
|
gSpecialFileImages[tile] = ibuf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IMB_freeImBuf(bbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_free_icons()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i=0; i < SPECIAL_IMG_MAX; ++i) {
|
|
|
|
IMB_freeImBuf(gSpecialFileImages[i]);
|
|
|
|
gSpecialFileImages[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 07:25:44 +00:00
|
|
|
//-----------------FOLDERLIST (previous/next) --------------//
|
|
|
|
struct ListBase* folderlist_new()
|
|
|
|
{
|
|
|
|
ListBase* p = MEM_callocN( sizeof(ListBase), "folderlist" );
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void folderlist_popdir(struct ListBase* folderlist, const char *dir)
|
|
|
|
{
|
|
|
|
const char *prev_dir;
|
|
|
|
struct FolderList *folder;
|
|
|
|
folder = folderlist->last;
|
|
|
|
|
|
|
|
if(folder){
|
|
|
|
// remove the current directory
|
|
|
|
MEM_freeN(folder->foldername);
|
|
|
|
BLI_freelinkN(folderlist, folder);
|
|
|
|
|
|
|
|
folder = folderlist->last;
|
|
|
|
if(folder){
|
|
|
|
prev_dir = folder->foldername;
|
|
|
|
BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// delete the folder next or use setdir directly before PREVIOUS OP
|
|
|
|
}
|
|
|
|
|
|
|
|
void folderlist_pushdir(ListBase* folderlist, const char *dir)
|
|
|
|
{
|
|
|
|
struct FolderList *folder, *previous_folder;
|
|
|
|
previous_folder = folderlist->last;
|
|
|
|
|
|
|
|
// check if already exists
|
|
|
|
if(previous_folder){
|
|
|
|
if(! strcmp(previous_folder->foldername, dir)){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create next folder element
|
|
|
|
folder = (FolderList*)MEM_mallocN(sizeof(FolderList),"FolderList");
|
|
|
|
folder->foldername = (char*)MEM_mallocN(sizeof(char)*(strlen(dir)+1), "foldername");
|
|
|
|
folder->foldername[0] = '\0';
|
|
|
|
|
|
|
|
BLI_strncpy(folder->foldername, dir, FILE_MAXDIR);
|
|
|
|
|
|
|
|
// add it to the end of the list
|
|
|
|
BLI_addtail(folderlist, folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
int folderlist_clear_next(struct SpaceFile *sfile)
|
|
|
|
{
|
|
|
|
struct FolderList *folder;
|
|
|
|
|
|
|
|
// if there is no folder_next there is nothing we can clear
|
|
|
|
if (!sfile->folders_next)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next
|
|
|
|
folder = sfile->folders_prev->last;
|
|
|
|
if ((!folder) ||(!strcmp(folder->foldername, sfile->params->dir)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// eventually clear flist->folders_next
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void folderlist_free(ListBase* folderlist)
|
|
|
|
{
|
|
|
|
FolderList *folder;
|
|
|
|
if (folderlist){
|
|
|
|
for(folder= folderlist->last; folder; folder= folderlist->last) {
|
|
|
|
MEM_freeN(folder->foldername);
|
|
|
|
BLI_freelinkN(folderlist, folder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
folderlist= NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------FILELIST------------------------//
|
2008-12-18 19:21:30 +00:00
|
|
|
struct FileList* filelist_new()
|
|
|
|
{
|
|
|
|
FileList* p = MEM_callocN( sizeof(FileList), "filelist" );
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FileList* filelist_copy(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
FileList* p = filelist_new();
|
|
|
|
BLI_strncpy(p->dir, filelist->dir, FILE_MAX);
|
|
|
|
p->filelist = NULL;
|
|
|
|
p->fidx = NULL;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_free(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!filelist) {
|
2009-07-07 07:25:44 +00:00
|
|
|
printf("Attempting to delete empty filelist.\n");
|
2008-12-18 19:21:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-18 18:24:11 +00:00
|
|
|
BLI_end_threads(&filelist->threads);
|
|
|
|
BLI_freelistN(&filelist->loadimages);
|
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
if (filelist->fidx) {
|
|
|
|
MEM_freeN(filelist->fidx);
|
|
|
|
filelist->fidx = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < filelist->numfiles; ++i) {
|
|
|
|
if (filelist->filelist[i].image) {
|
|
|
|
IMB_freeImBuf(filelist->filelist[i].image);
|
|
|
|
}
|
|
|
|
filelist->filelist[i].image = 0;
|
|
|
|
if (filelist->filelist[i].relname)
|
|
|
|
MEM_freeN(filelist->filelist[i].relname);
|
|
|
|
filelist->filelist[i].relname = 0;
|
|
|
|
if (filelist->filelist[i].string)
|
|
|
|
MEM_freeN(filelist->filelist[i].string);
|
|
|
|
filelist->filelist[i].string = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
filelist->numfiles = 0;
|
|
|
|
free(filelist->filelist);
|
|
|
|
filelist->filelist = 0;
|
|
|
|
filelist->filter = 0;
|
|
|
|
filelist->numfiltered =0;
|
2009-06-04 20:07:06 +00:00
|
|
|
filelist->hide_dot =0;
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int filelist_numfiles(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
return filelist->numfiltered;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * filelist_dir(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
return filelist->dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_setdir(struct FileList* filelist, const char *dir)
|
|
|
|
{
|
|
|
|
BLI_strncpy(filelist->dir, dir, FILE_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_imgsize(struct FileList* filelist, short w, short h)
|
|
|
|
{
|
|
|
|
filelist->prv_w = w;
|
|
|
|
filelist->prv_h = h;
|
|
|
|
}
|
|
|
|
|
2009-01-18 18:24:11 +00:00
|
|
|
|
|
|
|
static void *exec_loadimages(void *list_v)
|
|
|
|
{
|
|
|
|
FileImage* img = (FileImage*)list_v;
|
|
|
|
struct FileList *filelist = img->filelist;
|
|
|
|
|
|
|
|
ImBuf *imb = NULL;
|
|
|
|
int fidx = img->index;
|
|
|
|
|
|
|
|
if ( filelist->filelist[fidx].flags & IMAGEFILE ) {
|
|
|
|
imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_IMAGE);
|
|
|
|
} else if ( filelist->filelist[fidx].flags & MOVIEFILE ) {
|
|
|
|
imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_MOVIE);
|
|
|
|
if (!imb) {
|
|
|
|
/* remember that file can't be loaded via IMB_open_anim */
|
|
|
|
filelist->filelist[fidx].flags &= ~MOVIEFILE;
|
|
|
|
filelist->filelist[fidx].flags |= MOVIEFILE_ICON;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (imb) {
|
|
|
|
IMB_freeImBuf(imb);
|
|
|
|
}
|
|
|
|
img->done=1;
|
2009-01-18 18:35:24 +00:00
|
|
|
return 0;
|
2009-01-18 18:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
short filelist_changed(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
return filelist->changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_loadimage_timer(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
FileImage *limg = filelist->loadimages.first;
|
|
|
|
short refresh=0;
|
|
|
|
|
|
|
|
// as long as threads are available and there is work to do
|
|
|
|
while (limg) {
|
|
|
|
if (BLI_available_threads(&filelist->threads)>0) {
|
|
|
|
if (!limg->lock) {
|
|
|
|
limg->lock=1;
|
|
|
|
BLI_insert_thread(&filelist->threads, limg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (limg->done) {
|
|
|
|
FileImage *oimg = limg;
|
|
|
|
BLI_remlink(&filelist->loadimages, oimg);
|
|
|
|
BLI_remove_thread(&filelist->threads, oimg);
|
|
|
|
limg = oimg->next;
|
|
|
|
MEM_freeN(oimg);
|
|
|
|
refresh = 1;
|
|
|
|
} else {
|
|
|
|
limg= limg->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
filelist->changed=refresh;
|
|
|
|
}
|
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
void filelist_loadimage(struct FileList* filelist, int index)
|
|
|
|
{
|
|
|
|
ImBuf *imb = NULL;
|
|
|
|
int imgwidth = filelist->prv_w;
|
|
|
|
int imgheight = filelist->prv_h;
|
|
|
|
short ex, ey, dx, dy;
|
|
|
|
float scaledx, scaledy;
|
|
|
|
int fidx = 0;
|
|
|
|
|
|
|
|
if ( (index < 0) || (index >= filelist->numfiltered) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fidx = filelist->fidx[index];
|
|
|
|
|
|
|
|
if (!filelist->filelist[fidx].image)
|
|
|
|
{
|
2009-06-04 20:07:06 +00:00
|
|
|
|
|
|
|
if ( (filelist->filelist[fidx].flags & IMAGEFILE) || (filelist->filelist[fidx].flags & MOVIEFILE) ) {
|
|
|
|
imb = IMB_thumb_read(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL);
|
|
|
|
}
|
|
|
|
if (imb) {
|
|
|
|
if (imb->x > imb->y) {
|
|
|
|
scaledx = (float)imgwidth;
|
|
|
|
scaledy = ( (float)imb->y/(float)imb->x )*imgwidth;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scaledy = (float)imgheight;
|
|
|
|
scaledx = ( (float)imb->x/(float)imb->y )*imgheight;
|
|
|
|
}
|
|
|
|
ex = (short)scaledx;
|
|
|
|
ey = (short)scaledy;
|
|
|
|
|
|
|
|
dx = imgwidth - ex;
|
|
|
|
dy = imgheight - ey;
|
|
|
|
|
|
|
|
// IMB_scaleImBuf(imb, ex, ey);
|
|
|
|
filelist->filelist[fidx].image = imb;
|
|
|
|
} else {
|
|
|
|
/* prevent loading image twice */
|
|
|
|
FileImage* limg = filelist->loadimages.first;
|
|
|
|
short found= 0;
|
|
|
|
while(limg) {
|
|
|
|
if (limg->index == fidx) {
|
|
|
|
found= 1;
|
|
|
|
break;
|
2009-01-18 18:24:11 +00:00
|
|
|
}
|
2009-06-04 20:07:06 +00:00
|
|
|
limg= limg->next;
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
|
|
|
|
limg->index= fidx;
|
|
|
|
limg->lock= 0;
|
|
|
|
limg->filelist= filelist;
|
|
|
|
BLI_addtail(&filelist->loadimages, limg);
|
|
|
|
}
|
|
|
|
}
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ImBuf * filelist_getimage(struct FileList* filelist, int index)
|
|
|
|
{
|
|
|
|
ImBuf* ibuf = NULL;
|
|
|
|
int fidx = 0;
|
|
|
|
if ( (index < 0) || (index >= filelist->numfiltered) ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fidx = filelist->fidx[index];
|
|
|
|
ibuf = filelist->filelist[fidx].image;
|
|
|
|
|
2009-03-11 23:22:07 +00:00
|
|
|
return ibuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ImBuf * filelist_geticon(struct FileList* filelist, int index)
|
|
|
|
{
|
|
|
|
ImBuf* ibuf= NULL;
|
|
|
|
struct direntry *file= NULL;
|
|
|
|
int fidx = 0;
|
|
|
|
if ( (index < 0) || (index >= filelist->numfiltered) ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fidx = filelist->fidx[index];
|
|
|
|
file = &filelist->filelist[fidx];
|
|
|
|
if (file->type & S_IFDIR) {
|
2008-12-18 19:21:30 +00:00
|
|
|
if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
|
|
|
|
} else if ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
|
|
|
|
} else {
|
2009-03-11 23:22:07 +00:00
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
2009-03-11 23:22:07 +00:00
|
|
|
} else {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
|
|
|
|
}
|
2008-12-18 19:21:30 +00:00
|
|
|
|
2009-03-11 23:22:07 +00:00
|
|
|
if (file->flags & BLENDERFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
|
|
|
|
} else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
|
|
|
|
} else if (file->flags & SOUNDFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
|
|
|
|
} else if (file->flags & PYSCRIPTFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
|
|
|
|
} else if (file->flags & FTFONTFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
|
|
|
|
} else if (file->flags & TEXTFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
|
|
|
|
} else if (file->flags & IMAGEFILE) {
|
|
|
|
ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
2009-03-11 23:22:07 +00:00
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
return ibuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct direntry * filelist_file(struct FileList* filelist, int index)
|
|
|
|
{
|
|
|
|
int fidx = 0;
|
|
|
|
|
|
|
|
if ( (index < 0) || (index >= filelist->numfiltered) ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fidx = filelist->fidx[index];
|
|
|
|
|
|
|
|
return &filelist->filelist[fidx];
|
|
|
|
}
|
|
|
|
|
2009-05-14 18:08:14 +00:00
|
|
|
|
2008-12-18 19:21:30 +00:00
|
|
|
int filelist_find(struct FileList* filelist, char *file)
|
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
int i;
|
|
|
|
int fidx = -1;
|
|
|
|
|
|
|
|
if (!filelist->fidx)
|
|
|
|
return fidx;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < filelist->numfiles; ++i) {
|
|
|
|
if ( strcmp(filelist->filelist[i].relname, file) == 0) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < filelist->numfiltered; ++i) {
|
|
|
|
if (filelist->fidx[i] == index) {
|
|
|
|
fidx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_hidedot(struct FileList* filelist, short hide)
|
|
|
|
{
|
|
|
|
filelist->hide_dot = hide;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_setfilter(struct FileList* filelist, unsigned int filter)
|
|
|
|
{
|
|
|
|
filelist->filter = filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_readdir(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
char wdir[FILE_MAX];
|
|
|
|
|
|
|
|
if (!filelist) return;
|
|
|
|
filelist->fidx = 0;
|
|
|
|
filelist->filelist = 0;
|
|
|
|
|
2009-03-11 23:22:07 +00:00
|
|
|
BLI_getwdN(wdir);
|
|
|
|
|
|
|
|
BLI_cleanup_dir(G.sce, filelist->dir);
|
|
|
|
BLI_hide_dot_files(filelist->hide_dot);
|
|
|
|
filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist));
|
2008-12-18 19:21:30 +00:00
|
|
|
|
2009-03-11 23:22:07 +00:00
|
|
|
chdir(wdir);
|
|
|
|
filelist_setfiletypes(filelist, G.have_quicktime);
|
|
|
|
filelist_filter(filelist);
|
|
|
|
|
|
|
|
if (!filelist->threads.first) {
|
|
|
|
BLI_init_threads(&filelist->threads, exec_loadimages, 2);
|
2008-12-18 19:21:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int filelist_empty(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
return filelist->filelist == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_parent(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
BLI_parent_dir(filelist->dir);
|
|
|
|
BLI_make_exist(filelist->dir);
|
|
|
|
filelist_readdir(filelist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
|
|
|
|
{
|
|
|
|
struct direntry *file;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
file= filelist->filelist;
|
|
|
|
|
|
|
|
for(num=0; num<filelist->numfiles; num++, file++) {
|
|
|
|
file->flags= 0;
|
|
|
|
file->type= file->s.st_mode; /* restore the mess below */
|
|
|
|
|
|
|
|
/* Don't check extensions for directories */
|
|
|
|
if (file->type & S_IFDIR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(BLO_has_bfile_extension(file->relname)) {
|
|
|
|
file->flags |= BLENDERFILE;
|
|
|
|
} else if(BLI_testextensie(file->relname, ".py")) {
|
|
|
|
file->flags |= PYSCRIPTFILE;
|
|
|
|
} else if(BLI_testextensie(file->relname, ".txt")) {
|
|
|
|
file->flags |= TEXTFILE;
|
|
|
|
} else if( BLI_testextensie(file->relname, ".ttf")
|
|
|
|
|| BLI_testextensie(file->relname, ".ttc")
|
|
|
|
|| BLI_testextensie(file->relname, ".pfb")
|
|
|
|
|| BLI_testextensie(file->relname, ".otf")
|
|
|
|
|| BLI_testextensie(file->relname, ".otc")) {
|
|
|
|
file->flags |= FTFONTFILE;
|
|
|
|
} else if (has_quicktime){
|
|
|
|
if( BLI_testextensie(file->relname, ".int")
|
|
|
|
|| BLI_testextensie(file->relname, ".inta")
|
|
|
|
|| BLI_testextensie(file->relname, ".jpg")
|
2009-01-26 08:34:40 +00:00
|
|
|
#ifdef WITH_OPENJPEG
|
|
|
|
|| BLI_testextensie(file->relname, ".jp2")
|
|
|
|
#endif
|
2008-12-18 19:21:30 +00:00
|
|
|
|| BLI_testextensie(file->relname, ".jpeg")
|
|
|
|
|| BLI_testextensie(file->relname, ".tga")
|
|
|
|
|| BLI_testextensie(file->relname, ".rgb")
|
|
|
|
|| BLI_testextensie(file->relname, ".rgba")
|
|
|
|
|| BLI_testextensie(file->relname, ".bmp")
|
|
|
|
|| BLI_testextensie(file->relname, ".png")
|
|
|
|
|| BLI_testextensie(file->relname, ".iff")
|
|
|
|
|| BLI_testextensie(file->relname, ".lbm")
|
|
|
|
|| BLI_testextensie(file->relname, ".gif")
|
|
|
|
|| BLI_testextensie(file->relname, ".psd")
|
|
|
|
|| BLI_testextensie(file->relname, ".tif")
|
|
|
|
|| BLI_testextensie(file->relname, ".tiff")
|
|
|
|
|| BLI_testextensie(file->relname, ".pct")
|
|
|
|
|| BLI_testextensie(file->relname, ".pict")
|
|
|
|
|| BLI_testextensie(file->relname, ".pntg") //macpaint
|
|
|
|
|| BLI_testextensie(file->relname, ".qtif")
|
|
|
|
|| BLI_testextensie(file->relname, ".sgi")
|
|
|
|
|| BLI_testextensie(file->relname, ".hdr")
|
|
|
|
#ifdef WITH_DDS
|
|
|
|
|| BLI_testextensie(file->relname, ".dds")
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_OPENEXR
|
|
|
|
|| BLI_testextensie(file->relname, ".exr")
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
file->flags |= IMAGEFILE;
|
|
|
|
}
|
|
|
|
else if(BLI_testextensie(file->relname, ".avi")
|
|
|
|
|| BLI_testextensie(file->relname, ".flc")
|
|
|
|
|| BLI_testextensie(file->relname, ".mov")
|
|
|
|
|| BLI_testextensie(file->relname, ".movie")
|
|
|
|
|| BLI_testextensie(file->relname, ".mp4")
|
|
|
|
|| BLI_testextensie(file->relname, ".m4v")
|
|
|
|
|| BLI_testextensie(file->relname, ".mv")) {
|
|
|
|
file->flags |= MOVIEFILE;
|
|
|
|
}
|
|
|
|
else if(BLI_testextensie(file->relname, ".wav")) {
|
|
|
|
file->flags |= SOUNDFILE;
|
|
|
|
}
|
|
|
|
} else { // no quicktime
|
|
|
|
if(BLI_testextensie(file->relname, ".int")
|
|
|
|
|| BLI_testextensie(file->relname, ".inta")
|
|
|
|
|| BLI_testextensie(file->relname, ".jpg")
|
2009-01-26 08:34:40 +00:00
|
|
|
|| BLI_testextensie(file->relname, ".jpeg")
|
|
|
|
#ifdef WITH_OPENJPEG
|
|
|
|
|| BLI_testextensie(file->relname, ".jp2")
|
|
|
|
#endif
|
2008-12-18 19:21:30 +00:00
|
|
|
|| BLI_testextensie(file->relname, ".tga")
|
|
|
|
|| BLI_testextensie(file->relname, ".rgb")
|
|
|
|
|| BLI_testextensie(file->relname, ".rgba")
|
|
|
|
|| BLI_testextensie(file->relname, ".bmp")
|
|
|
|
|| BLI_testextensie(file->relname, ".png")
|
|
|
|
|| BLI_testextensie(file->relname, ".iff")
|
|
|
|
|| BLI_testextensie(file->relname, ".tif")
|
|
|
|
|| BLI_testextensie(file->relname, ".tiff")
|
|
|
|
|| BLI_testextensie(file->relname, ".hdr")
|
|
|
|
#ifdef WITH_DDS
|
|
|
|
|| BLI_testextensie(file->relname, ".dds")
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_OPENEXR
|
|
|
|
|| BLI_testextensie(file->relname, ".exr")
|
|
|
|
#endif
|
|
|
|
|| BLI_testextensie(file->relname, ".lbm")
|
|
|
|
|| BLI_testextensie(file->relname, ".sgi")) {
|
|
|
|
file->flags |= IMAGEFILE;
|
|
|
|
}
|
|
|
|
else if(BLI_testextensie(file->relname, ".avi")
|
|
|
|
|| BLI_testextensie(file->relname, ".mp4")
|
|
|
|
|| BLI_testextensie(file->relname, ".mv")) {
|
|
|
|
file->flags |= MOVIEFILE;
|
|
|
|
}
|
|
|
|
else if(BLI_testextensie(file->relname, ".wav")) {
|
|
|
|
file->flags |= SOUNDFILE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_swapselect(struct FileList* filelist)
|
|
|
|
{
|
|
|
|
struct direntry *file;
|
|
|
|
int num, act= 0;
|
|
|
|
|
|
|
|
file= filelist->filelist;
|
|
|
|
for(num=0; num<filelist->numfiles; num++, file++) {
|
|
|
|
if(file->flags & ACTIVE) {
|
|
|
|
act= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
file= filelist->filelist+2;
|
|
|
|
for(num=2; num<filelist->numfiles; num++, file++) {
|
|
|
|
if(act) file->flags &= ~ACTIVE;
|
|
|
|
else file->flags |= ACTIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void filelist_sort(struct FileList* filelist, short sort)
|
|
|
|
{
|
|
|
|
struct direntry *file;
|
|
|
|
int num;/* , act= 0; */
|
|
|
|
|
|
|
|
switch(sort) {
|
2009-06-29 20:23:40 +00:00
|
|
|
case FILE_SORT_ALPHA:
|
2008-12-18 19:21:30 +00:00
|
|
|
qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);
|
|
|
|
break;
|
2009-06-29 20:23:40 +00:00
|
|
|
case FILE_SORT_TIME:
|
2008-12-18 19:21:30 +00:00
|
|
|
qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);
|
|
|
|
break;
|
2009-06-29 20:23:40 +00:00
|
|
|
case FILE_SORT_SIZE:
|
2008-12-18 19:21:30 +00:00
|
|
|
qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);
|
|
|
|
break;
|
2009-06-29 20:23:40 +00:00
|
|
|
case FILE_SORT_EXTENSION:
|
2008-12-18 19:21:30 +00:00
|
|
|
qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);
|
|
|
|
}
|
|
|
|
|
|
|
|
file= filelist->filelist;
|
|
|
|
for(num=0; num<filelist->numfiles; num++, file++) {
|
|
|
|
file->flags &= ~HILITE;
|
|
|
|
}
|
|
|
|
filelist_filter(filelist);
|
|
|
|
}
|