Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - minimimi

#1
I just made a VC++ projects for raw2dng
https://bitbucket.org/minimimi/magic-lantern-raw2dng_vc

see contrib/raw2dng_vc dir.

I'm imported raw2dng.c to main app  and using C++ class version chdk-dng.c
#2
I see. It's one of solution for current our knowlege.
And , pushed small pathces for "src&dst files are idential " and "cleanup memory when unloading".
Please review it.
#3
Thanks your daily cooperation and polish it up. :D
I think we need to add some more miner chagens. When I make it, I will make a pull req.

-we need skip , when src & dst files are idential
-disable automatic power save (However we can't use half-push tric here. and we don't wanna change NVRAM value...)
#4
Ah! You already delete it Alex.


Anyway, I think ASCII and UTF-8 is compatible when we use only ASCII chars.
I will try to find convert issue on my own equipment.

Modified
You already solved this , I can read current XMP to ACR directly.
#5
Alex,
The first 1byte is some special char. But it's really strange. I'm checked codes, But i cant find bug.
- FILE* f is not move when we do my_printf
-xmp_template has no special char.



@RenatoPhto
Got it.
Notepad delete first special char.
UTF-8 converte is successfully convert 1byte strange char to UTF-8 , so we can read it.

My guess is fault. All files are using "\n".
#6
@RenatoPhoto

Are you using Adobe on Windows??

It's just my guess, Current code  generated  a "\n" return code.
But Windows using "\r\n". 
Ofcource Windows understanding both "\n" and "\r\n" but it's depend on software programmer(depend on which Windows API use).

So UTF-8 converter is automatically convert retrun code, then we can use xmp , I guess.
If you have both(befor/converted) zip and share it. I can confirm it

#7
https://bitbucket.org/minimimi/magic-lantern-filer-multiselect/compare/hudson/magic-lantern:unified..unified#chg-modules/file_man/file_man.c

see here.
If you have no problem, enbale selectQ plz for multiple file selection.


Modified
Alex. sorry for confusing. I just understood you are not disable Q everyware. So I can solve myself.
#8
Alex:
Oh! important point is conflicted.

Are you already disabled "Q" ??
#9
I got it. Never use ifdefs in modules.
Then, how do you think about M 1%?
#10
1%
I mean , use ifdef for :
-disable Q
-show "../"
Then you can use file manager with cursol keys. Is this a correct understanding?

I think almost fine on my multiple select codes. please check it except M(sorry.
#11
https://bitbucket.org/minimimi/magic-lantern-filer-multiselect

basic functions are working. push file twice.

now debugging
-already registerd check when we push copy menu.
-cancel copy operation when we un-select all files

1% ,
we need "../" ?? or need ifdef for EOSM?
#12
OK!!!!
I found answer for multiple file selection!!!!!
Soon will open new repo.
Already , almost codes are working. Yay, wait a moment
#13
G3gg0 and Alex

Thank you for your merge/implove/brush up.
It's perfect for me. I'm using 64gig SD and 32gig CF. So I wanted to move RAW to SD.

Maybe here and
http://www.magiclantern.fm/forum/index.php?topic=5936.new#new
are close-able.

Multiple file selection is future TODO...I have no idea to make multiple file selection now...
#14
Already deleted "../" by alex.(lol

#15
Yes. But this file browser has multiple hierarchy. So I think "../" sign is good for understanding it.
You have enough skills I guess. So  you don't need it. But I think all of users has not enough skills like you.

I guess someone make a new feature request which is "pls add ../ " near future.
So I mean , it's a each persons preference.

Anyway, We must make a core functions for file browser itserlf(copy/move/multiple select/progress) first.
Then , we are looking for best GUI interface IMHO.

If you agree, your first request , Please close this request. And If you want to remove "../", make a new request when we finish to make a core functions of file browser.

See also:
http://www.magiclantern.fm/forum/index.php?topic=5522.new#new
#16
Quote from: g3gg0 on June 01, 2013, 09:57:57 PM
ah sorry, i already checked in your new source code.
just wanted to write that here then i saw you forked on bitbucket :)

You already have write permission on my repo. Because I'm used same permission with main repo.
#17
G3gg0:
Thanks , I already used alex method(Used TYPE_ACTION).But I'm override menu_entry->update myself.It was problem. Solved it now.
And , I'm also thinking RAW playback from filer.
See here.
enum _FILER_OP {
    FILE_OP_NONE,
    FILE_OP_COPY,
    FILE_OP_MOVE,
    FILE_OP_PREVIEW
};



So I want to know, how to know raw_rac.mo is already loaded, and how to call funcstion in anothers.
If you have a patch file, share it please,

Alex:
Thanks suggestions for making Progress. Will try it.

ScanDir things. need a "menu_sem" ? . So I added functions in menu.c in previous codes src/filer.c version.
Need to add, GetSemWrapper()/ReleaseSemWrapper() in menu.c?
Is this better way? How do you think?
#18
Yes same meaning.
Because, If you first time to see the menu, You don't know the "Q means a Browse Up ".
It means a lot of asking are comming to forum, and devs need to asnwer it.
#19
made a repo
https://bitbucket.org/minimimi/magic-lantern-filer-alex-based

and Found reason for number issue . Solved it now.
Next, I will think about how to implement multiple-selection and "file operation status window".
#20
I just found this code.
static MENU_UPDATE_FUNC(update_action)
{
    MENU_SET_VALUE("");
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

it means a , current browsing path is shown on bottom of the LCD. So may be I think that this request is able to close.

If you agree this , Please add [done] sign on the title bar.

#21
Added ScanDir() when it finished copy/move functions and still showing same dir.

#define CONFIG_CONSOLE

#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>

#define MAX_PATH_LEN 0x80
static char gPath[MAX_PATH_LEN];
static char gSrcFile[MAX_PATH_LEN];
static unsigned int op_mode;

static int cf_present;
static int sd_present;

struct file_entry
{
    struct file_entry * next;
    struct menu_entry menu_entry;
    char name[MAX_PATH_LEN];
    unsigned int size;
    unsigned int type: 2;
    unsigned int added: 1;
};

#define TYPE_DIR 0
#define TYPE_FILE 1
#define TYPE_ACTION 2

enum _FILER_OP {
    FILE_OP_NONE,
    FILE_OP_COPY,
    FILE_OP_MOVE,
    FILE_OP_PREVIEW
};

static struct file_entry * file_entries = 0;

/* view file mode */
static int view_file = 0;

static MENU_SELECT_FUNC(select_dir);
static MENU_UPDATE_FUNC(update_dir);
static MENU_SELECT_FUNC(select_file);
static MENU_UPDATE_FUNC(update_file);
static MENU_SELECT_FUNC(default_select_action);
static MENU_UPDATE_FUNC(update_action);
static MENU_SELECT_FUNC(BrowseUpMenu);

static struct menu_entry fileman_menu[] =
{
    {
        .name = "File Browser",
        .select = menu_open_submenu,
        .submenu_width = 710,
        .children =  (struct menu_entry[]) {
            MENU_EOL,
        }
    }
};

static void clear_file_menu()
{
    while (file_entries)
    {
        struct file_entry * next = file_entries->next;
        menu_remove("File Browser", &(file_entries->menu_entry), 1);
        console_printf("%s\n", file_entries->name);
        FreeMemory(file_entries);
        file_entries = next;
    }
}

static struct file_entry * add_file_entry(char* txt, int type, int size)
{
    struct file_entry * fe = AllocateMemory(sizeof(struct file_entry));
    if (!fe) return 0;
    memset(fe, 0, sizeof(struct file_entry));
    snprintf(fe->name, sizeof(fe->name), "%s", txt);
    fe->size = size;

    fe->menu_entry.name = fe->name;
    fe->menu_entry.priv = fe;

    fe->type = type;
    fe->menu_entry.select_Q = BrowseUpMenu;
    if (fe->type == TYPE_DIR)
    {
        fe->menu_entry.select = select_dir;
        fe->menu_entry.update = update_dir;
    }
    else if (fe->type == TYPE_FILE)
    {
        fe->menu_entry.select = select_file;
        fe->menu_entry.update = update_file;
    }
    else if (fe->type == TYPE_ACTION)
    {
        fe->menu_entry.select = default_select_action;
        fe->menu_entry.update = update_action;
        fe->menu_entry.icon_type = IT_ACTION;
    }
    fe->next = file_entries;
    file_entries = fe;
    return fe;
}

static void build_file_menu()
{
    /* HaCKeD Sort */
    int done = 0;
    while (!done)
    {
        done = 1;

        for (struct file_entry * fe = file_entries; fe; fe = fe->next)
        {
            if (!fe->added)
            {
                /* are there any entries that should be before "fe" ? */
                /* if yes, skip "fe", add those entries, and try again */
                int should_skip = 0;
                for (struct file_entry * e = file_entries; e; e = e->next)
                {
                    if (!e->added && e != fe)
                    {
                        if (e->type < fe->type) { should_skip = 1; break; }
                        if ((e->type == fe->type) && strcmp(e->name, fe->name) < 0) { should_skip = 1; break; }
                    }
                }

                if (!should_skip)
                {
                    menu_add("File Browser", &(fe->menu_entry), 1);
                    fe->added = 1;
                }
                else done = 0;
            }
        }
    }
}

static void ScanDir(char *path)
{
    clear_file_menu();

    if (strlen(path) == 0)
    {
        add_file_entry("A:/", TYPE_DIR, 0);
        add_file_entry("B:/", TYPE_DIR, 0);
        build_file_menu();
        return;
    }

    if(op_mode != FILE_OP_NONE)
    {
        console_printf("ScanDir\n");
        char srcpath[MAX_PATH_LEN];
        strcpy(srcpath,gSrcFile);
        char *p = srcpath+strlen(srcpath);
        while (p > srcpath && *p != '/') p--;
        *(p+1) = 0;

        console_printf("src: %s\n",srcpath);
        console_printf("dst: %s\n",path);


        if(strcmp(path,srcpath) != 0){
            add_file_entry("***Select Here***", TYPE_DIR, 0);
            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
        }
    }


    add_file_entry("../", TYPE_DIR, 0);

    struct fio_file file;
    struct fio_dirent * dirent = 0;

    dirent = FIO_FindFirstEx( path, &file );
    if( IS_ERROR(dirent) )
    {
        build_file_menu();
        return;
    }

    do
    {
        if (file.name[0] == '.') continue;
        if (file.mode & ATTR_DIRECTORY)
        {
            int len = strlen(file.name);
            snprintf(file.name + len, sizeof(file.name) - len, "/");
            add_file_entry(file.name, TYPE_DIR, 0);
        }
        else
        {
            add_file_entry(file.name, TYPE_FILE, file.size);
        }
    }
    while( FIO_FindNextEx( dirent, &file ) == 0);

    build_file_menu();

    FIO_CleanupAfterFindNext_maybe(dirent);
}

static void Browse(char* path)
{
    snprintf(gPath, sizeof(gPath), path);
    ScanDir(gPath);
}

static void BrowseDown(char* path)
{
    STR_APPEND(gPath, "%s", path);
    ScanDir(gPath);
}

static void restore_menu_selection(char* old_dir)
{
    for (struct file_entry * fe = file_entries; fe; fe = fe->next)
    {
        if (streq(fe->name, old_dir))
        {
            fe->menu_entry.selected = 1;
            for (struct file_entry * e = file_entries; e; e = e->next)
                if (e != fe) e->menu_entry.selected = 0;
            break;
        }
    }
}

static void BrowseUp()
{
    char* p = gPath + strlen(gPath) - 2;
    while (p > gPath && *p != '/') p--;

    if (*p == '/') /* up one level */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), p+1);
        *(p+1) = 0;
        ScanDir(gPath);
        restore_menu_selection(old_dir);
    }
    else if (cf_present && sd_present && strlen(gPath) > 0) /* two cards: show A:/ and B:/ in menu */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), "%s", gPath);
        gPath[0] = 0;
        ScanDir("");
        restore_menu_selection(old_dir);
    }
    else /* already at the top, close the file browser */
    {
        menu_close_submenu();
    }
}

static int
ML_FIO_CopyFile(char *src,char *dst){
    const int bufsize = 128*1024;
    void* buf = alloc_dma_memory(bufsize);
    if (!buf) return 1;

    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
    if (f == INVALID_PTR) return 1;

    FILE* g = FIO_CreateFileEx(dst);
    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }

    int r = 0;
    while ((r = FIO_ReadFile(f, buf, bufsize)))
        FIO_WriteFile(g, buf, r);

    FIO_CloseFile(f);
    FIO_CloseFile(g);
    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
    free_dma_memory(buf);
    return 0;
}

static int
ML_FIO_MoveFile(char *src,char *dst){

    ML_FIO_CopyFile(src,dst);
    FIO_RemoveFile(src);
    return 0;
}

static void
FileCopy(void *unused)
{
    char fname[MAX_PATH_LEN],tmpdst[MAX_PATH_LEN];
    strcpy(tmpdst,gPath);
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    ML_FIO_CopyFile(gSrcFile,dstfile);

    if(!strcmp(gPath,tmpdst)) ScanDir(gPath);
}

static void
FileMove(void *unused)
{
    char fname[MAX_PATH_LEN],tmpdst[MAX_PATH_LEN];
    strcpy(tmpdst,gPath);
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Move\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_MoveFile(gSrcFile,dstfile);

    if(!strcmp(gPath,tmpdst)) ScanDir(gPath);
}


static void FileOperation(){

    switch(op_mode){
    case FILE_OP_COPY:
        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
        break;
    case FILE_OP_MOVE:
        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
        break;
    case FILE_OP_PREVIEW:
        break;
    }
    //cleanup
    op_mode = FILE_OP_NONE;

    ScanDir(gPath);
}

static void FileOpCancel(){
    gSrcFile[0] = 0;
    op_mode = FILE_OP_NONE;
    ScanDir(gPath);
}

static MENU_SELECT_FUNC(BrowseUpMenu)
{
    BrowseUp();
}

static MENU_SELECT_FUNC(select_dir)
{
    struct file_entry * fe = (struct file_entry *) priv;
    char* name = (char*) fe->name;
    if(!strcmp(name,"***Select Here***")){
        FileOperation();
    }else if(!strcmp(name,"*** Cancel OP ***")){
        FileOpCancel();
    }else if (!strcmp(name,"../") || (delta < 0))
        {
            BrowseUp();
        }
    else
        {
            BrowseDown(name);
        }
}

static MENU_UPDATE_FUNC(update_dir)
{
    MENU_SET_VALUE("");
    MENU_SET_ICON(MNI_AUTO, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

const char * format_size( unsigned size)
{
    static char str[ 32 ];

    if( size > 1024*1024*1024 )
    {
        int size_gb = (size/1024 + 5) * 10 / 1024 / 1024;
        snprintf( str, sizeof(str), "%d.%dGB", size_gb/10, size_gb%10);
    }
    else if( size > 1024*1024 )
    {
        int size_mb = (size/1024 + 5) * 10 / 1024;
        snprintf( str, sizeof(str), "%d.%dMB", size_mb/10, size_mb%10);
    }
    else if( size > 1024 )
    {
        int size_kb = (size/1024 + 5) * 10;
        snprintf( str, sizeof(str), "%d.%dkB", size_kb/10, size_kb%10);
    }
    else
    {
        snprintf( str, sizeof(str), "%db", size);
    }

    return str;
}

static MENU_SELECT_FUNC(CopyFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Copysrc: %s\n",gSrcFile);
    op_mode = FILE_OP_COPY;
}

static MENU_UPDATE_FUNC(CopyFileProgress)
{

}

static MENU_SELECT_FUNC(MoveFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Movesrc: %s\n",gSrcFile);
    op_mode = FILE_OP_MOVE;
}

static MENU_UPDATE_FUNC(MoveFileProgress)
{

}

static MENU_SELECT_FUNC(viewfile_toggle)
{
    view_file = !view_file;
}

static MENU_UPDATE_FUNC(viewfile_show)
{
    if (view_file)
    {
        static char buf[1025];
        FILE * file = FIO_Open( gPath, O_RDONLY | O_SYNC );
        if (file != INVALID_PTR)
        {
            int r = FIO_ReadFile(file, buf, sizeof(buf)-1);
            FIO_CloseFile(file);
            buf[r] = 0;
            info->custom_drawing = CUSTOM_DRAW_THIS_MENU;
            clrscr();
            big_bmp_printf(FONT_MED, 0, 0, "%s", buf);
        }
        else
        {
            MENU_SET_WARNING(MENU_WARN_ADVICE, "Error reading %s", gPath);
            view_file = 0;
        }
    }
    else
    {
        update_action(entry, info);
    }
}

static int delete_confirm_flag = 0;

static MENU_SELECT_FUNC(delete_file)
{
    if (streq(gPath+1, ":/AUTOEXEC.BIN"))
    {
        beep();
        return;
    }

    if (!delete_confirm_flag)
    {
        delete_confirm_flag = get_ms_clock_value();
        beep();
    }
    else
    {
        delete_confirm_flag = 0;
        FIO_RemoveFile(gPath);
        BrowseUp();
    }
}

static MENU_UPDATE_FUNC(delete_confirm)
{
    update_action(entry, info);

    /* delete confirmation timeout after 2 seconds */
    if (get_ms_clock_value() > delete_confirm_flag + 2000)
        delete_confirm_flag = 0;

    /* no question mark in in our font, fsck! */
    if (delete_confirm_flag)
        MENU_SET_RINFO("Press SET to confirm");
}

static MENU_SELECT_FUNC(select_file)
{
    struct file_entry * fe = (struct file_entry *) priv;

    /* fe will be freed in clear_file_menu; backup things that we are going to reuse */
    char name[MAX_PATH_LEN];
    snprintf(name, sizeof(name), "%s", fe->name);
    int size = fe->size;
    STR_APPEND(gPath, "%s", name);

    clear_file_menu();
    /* at this point, fe was freed and is no longer valid */
    fe = 0;

    struct file_entry * e = add_file_entry(name, TYPE_FILE, size);
    if (!e) return;
    e->menu_entry.select = BrowseUpMenu;
    e->menu_entry.select_Q = BrowseUpMenu;
    e->menu_entry.priv = e;

    e = add_file_entry("Copy", TYPE_ACTION, 0);
    e->menu_entry.select = CopyFile;
    e->menu_entry.update = CopyFileProgress;

    e = add_file_entry("Move", TYPE_ACTION, 0);
    e->menu_entry.select = MoveFile;
    e->menu_entry.update = MoveFileProgress;

    e = add_file_entry("View", TYPE_ACTION, 0);
    e->menu_entry.select = viewfile_toggle;
    e->menu_entry.update = viewfile_show;

    e = add_file_entry("Delete", TYPE_ACTION, 0);
    e->menu_entry.select = delete_file;
    e->menu_entry.update = delete_confirm;

    //~ e = add_file_entry("Copy", TYPE_ACTION, 0);
    //~ e = add_file_entry("Rename", TYPE_ACTION, 0);

    build_file_menu();
}

static MENU_UPDATE_FUNC(update_file)
{
    struct file_entry * fe = (struct file_entry *) entry->priv;
    MENU_SET_VALUE("");

    MENU_SET_RINFO("%s", format_size(fe->size));
    MENU_SET_ICON(MNI_OFF, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static MENU_SELECT_FUNC(default_select_action)
{
    beep();
}

static MENU_UPDATE_FUNC(update_action)
{
    MENU_SET_VALUE("");
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static int InitRootDir()
{
    cf_present = is_dir("A:/");
    sd_present = is_dir("B:/");

    if (cf_present && !sd_present)
    {
        Browse("A:/");
    }
    else if (sd_present && !cf_present)
    {
        Browse("B:/");
    }
    else if (sd_present && cf_present)
    {
        Browse("");
    }
    else return -1;

    return 0;
}

unsigned int fileman_init()
{
    menu_add("Debug", fileman_menu, COUNT(fileman_menu));
    op_mode = FILE_OP_NONE;
    InitRootDir();
    return 0;
}

unsigned int fileman_deinit()
{
    return 0;
}


MODULE_INFO_START()
    MODULE_INIT(fileman_init)
    MODULE_DEINIT(fileman_deinit)
MODULE_INFO_END()

MODULE_STRINGS_START()
    MODULE_STRING("Author", "ML dev.")
    MODULE_STRING("License", "GPL")
    MODULE_STRING("Description", "File browser")
MODULE_STRINGS_END()
#22
Thanks alex , I'm tested CreatefileEx(). It's succeed to overwrite with same filename.
#23
Oh, OK.
I'm only used FIO_CreateFile() , so maybe Dryos make a 2 different i-node files with same filename.
I need to overwrite check and use FIO_Open for overwrite.
#24
1% I see.
And now , Copy and Move menu entry has some strange numbers shown on same line. I guess it's referenced from info->xx but I can't solve it now.


#define CONFIG_CONSOLE

#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>

#define MAX_PATH_LEN 0x80
static char gPath[MAX_PATH_LEN];
static char gSrcFile[MAX_PATH_LEN];
static unsigned int op_mode;

static int cf_present;
static int sd_present;

struct file_entry
{
    struct file_entry * next;
    struct menu_entry menu_entry;
    char name[MAX_PATH_LEN];
    unsigned int size;
    unsigned int type: 2;
    unsigned int added: 1;
};

#define TYPE_DIR 0
#define TYPE_FILE 1
#define TYPE_ACTION 2

enum _FILER_OP {
    FILE_OP_NONE,
    FILE_OP_COPY,
    FILE_OP_MOVE,
    FILE_OP_PREVIEW
};

static struct file_entry * file_entries = 0;

/* view file mode */
static int view_file = 0;

static MENU_SELECT_FUNC(select_dir);
static MENU_UPDATE_FUNC(update_dir);
static MENU_SELECT_FUNC(select_file);
static MENU_UPDATE_FUNC(update_file);
static MENU_SELECT_FUNC(default_select_action);
static MENU_UPDATE_FUNC(update_action);
static MENU_SELECT_FUNC(BrowseUpMenu);

static struct menu_entry fileman_menu[] =
{
    {
        .name = "File Browser",
        .select = menu_open_submenu,
        .submenu_width = 710,
        .children =  (struct menu_entry[]) {
            MENU_EOL,
        }
    }
};

static void clear_file_menu()
{
    while (file_entries)
    {
        struct file_entry * next = file_entries->next;
        menu_remove("File Browser", &(file_entries->menu_entry), 1);
        console_printf("%s\n", file_entries->name);
        FreeMemory(file_entries);
        file_entries = next;
    }
}

static struct file_entry * add_file_entry(char* txt, int type, int size)
{
    struct file_entry * fe = AllocateMemory(sizeof(struct file_entry));
    if (!fe) return 0;
    memset(fe, 0, sizeof(struct file_entry));
    snprintf(fe->name, sizeof(fe->name), "%s", txt);
    fe->size = size;

    fe->menu_entry.name = fe->name;
    fe->menu_entry.priv = fe;

    fe->type = type;
    fe->menu_entry.select_Q = BrowseUpMenu;
    if (fe->type == TYPE_DIR)
    {
        fe->menu_entry.select = select_dir;
        fe->menu_entry.update = update_dir;
    }
    else if (fe->type == TYPE_FILE)
    {
        fe->menu_entry.select = select_file;
        fe->menu_entry.update = update_file;
    }
    else if (fe->type == TYPE_ACTION)
    {
        fe->menu_entry.select = default_select_action;
        fe->menu_entry.update = update_action;
        fe->menu_entry.icon_type = IT_ACTION;
    }
    fe->next = file_entries;
    file_entries = fe;
    return fe;
}

static void build_file_menu()
{
    /* HaCKeD Sort */
    int done = 0;
    while (!done)
    {
        done = 1;

        for (struct file_entry * fe = file_entries; fe; fe = fe->next)
        {
            if (!fe->added)
            {
                /* are there any entries that should be before "fe" ? */
                /* if yes, skip "fe", add those entries, and try again */
                int should_skip = 0;
                for (struct file_entry * e = file_entries; e; e = e->next)
                {
                    if (!e->added && e != fe)
                    {
                        if (e->type < fe->type) { should_skip = 1; break; }
                        if ((e->type == fe->type) && strcmp(e->name, fe->name) < 0) { should_skip = 1; break; }
                    }
                }

                if (!should_skip)
                {
                    menu_add("File Browser", &(fe->menu_entry), 1);
                    fe->added = 1;
                }
                else done = 0;
            }
        }
    }
}

static void ScanDir(char *path)
{
    clear_file_menu();

    if (strlen(path) == 0)
    {
        add_file_entry("A:/", TYPE_DIR, 0);
        add_file_entry("B:/", TYPE_DIR, 0);
        build_file_menu();
        return;
    }

    if(op_mode != FILE_OP_NONE)
    {
        console_printf("ScanDir\n");
        char srcpath[MAX_PATH_LEN];
        strcpy(srcpath,gSrcFile);
        char *p = srcpath+strlen(srcpath);
        while (p > srcpath && *p != '/') p--;
        *(p+1) = 0;

        console_printf("src: %s\n",srcpath);
        console_printf("dst: %s\n",path);


        if(strcmp(path,srcpath) != 0){
            add_file_entry("***Select Here***", TYPE_DIR, 0);
            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
        }
    }


    add_file_entry("../", TYPE_DIR, 0);

    struct fio_file file;
    struct fio_dirent * dirent = 0;

    dirent = FIO_FindFirstEx( path, &file );
    if( IS_ERROR(dirent) )
    {
        build_file_menu();
        return;
    }

    do
    {
        if (file.name[0] == '.') continue;
        if (file.mode & ATTR_DIRECTORY)
        {
            int len = strlen(file.name);
            snprintf(file.name + len, sizeof(file.name) - len, "/");
            add_file_entry(file.name, TYPE_DIR, 0);
        }
        else
        {
            add_file_entry(file.name, TYPE_FILE, file.size);
        }
    }
    while( FIO_FindNextEx( dirent, &file ) == 0);

    build_file_menu();

    FIO_CleanupAfterFindNext_maybe(dirent);
}

static void Browse(char* path)
{
    snprintf(gPath, sizeof(gPath), path);
    ScanDir(gPath);
}

static void BrowseDown(char* path)
{
    STR_APPEND(gPath, "%s", path);
    ScanDir(gPath);
}

static void restore_menu_selection(char* old_dir)
{
    for (struct file_entry * fe = file_entries; fe; fe = fe->next)
    {
        if (streq(fe->name, old_dir))
        {
            fe->menu_entry.selected = 1;
            for (struct file_entry * e = file_entries; e; e = e->next)
                if (e != fe) e->menu_entry.selected = 0;
            break;
        }
    }
}

static void BrowseUp()
{
    char* p = gPath + strlen(gPath) - 2;
    while (p > gPath && *p != '/') p--;

    if (*p == '/') /* up one level */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), p+1);
        *(p+1) = 0;
        ScanDir(gPath);
        restore_menu_selection(old_dir);
    }
    else if (cf_present && sd_present && strlen(gPath) > 0) /* two cards: show A:/ and B:/ in menu */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), "%s", gPath);
        gPath[0] = 0;
        ScanDir("");
        restore_menu_selection(old_dir);
    }
    else /* already at the top, close the file browser */
    {
        menu_close_submenu();
    }
}

static int
ML_FIO_CopyFile(char *src,char *dst){
    const int bufsize = 128*1024;
    void* buf = alloc_dma_memory(bufsize);
    if (!buf) return 1;

    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
    if (f == INVALID_PTR) return 1;

    FILE* g = FIO_CreateFile(dst);
    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }

    int r = 0;
    while ((r = FIO_ReadFile(f, buf, bufsize)))
        FIO_WriteFile(g, buf, r);

    FIO_CloseFile(f);
    FIO_CloseFile(g);
    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
    free_dma_memory(buf);
    return 0;
}

static int
ML_FIO_MoveFile(char *src,char *dst){

    ML_FIO_CopyFile(src,dst);
    FIO_RemoveFile(src);
    return 0;
}

static void
FileCopy(void *unused)
{
    char fname[MAX_PATH_LEN];
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Copy\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_CopyFile(gSrcFile,dstfile);

}

static void
FileMove(void *unused)
{
    char fname[MAX_PATH_LEN];
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Move\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_MoveFile(gSrcFile,dstfile);

}


static void FileOperation(){

    switch(op_mode){
    case FILE_OP_COPY:
        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
        break;
    case FILE_OP_MOVE:
        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
        break;
    case FILE_OP_PREVIEW:
        break;
    }
    //cleanup
    op_mode = FILE_OP_NONE;

    ScanDir(gPath);
}

static void FileOpCancel(){
    gSrcFile[0] = 0;
    op_mode = FILE_OP_NONE;
    ScanDir(gPath);
}

static MENU_SELECT_FUNC(BrowseUpMenu)
{
    BrowseUp();
}

static MENU_SELECT_FUNC(select_dir)
{
    struct file_entry * fe = (struct file_entry *) priv;
    char* name = (char*) fe->name;
    if(!strcmp(name,"***Select Here***")){
        FileOperation();
    }else if(!strcmp(name,"*** Cancel OP ***")){
        FileOpCancel();
    }else if (!strcmp(name,"../") || (delta < 0))
        {
            BrowseUp();
        }
    else
        {
            BrowseDown(name);
        }
}

static MENU_UPDATE_FUNC(update_dir)
{
    MENU_SET_VALUE("");
    MENU_SET_ICON(MNI_AUTO, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

const char * format_size( unsigned size)
{
    static char str[ 32 ];

    if( size > 1024*1024*1024 )
    {
        int size_gb = (size/1024 + 5) * 10 / 1024 / 1024;
        snprintf( str, sizeof(str), "%d.%dGB", size_gb/10, size_gb%10);
    }
    else if( size > 1024*1024 )
    {
        int size_mb = (size/1024 + 5) * 10 / 1024;
        snprintf( str, sizeof(str), "%d.%dMB", size_mb/10, size_mb%10);
    }
    else if( size > 1024 )
    {
        int size_kb = (size/1024 + 5) * 10;
        snprintf( str, sizeof(str), "%d.%dkB", size_kb/10, size_kb%10);
    }
    else
    {
        snprintf( str, sizeof(str), "%db", size);
    }

    return str;
}

static MENU_SELECT_FUNC(CopyFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Copysrc: %s\n",gSrcFile);
    op_mode = FILE_OP_COPY;
}

static MENU_UPDATE_FUNC(CopyFileProgress)
{

}

static MENU_SELECT_FUNC(MoveFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Movesrc: %s\n",gSrcFile);
    op_mode = FILE_OP_MOVE;
}

static MENU_UPDATE_FUNC(MoveFileProgress)
{

}

static MENU_SELECT_FUNC(viewfile_toggle)
{
    view_file = !view_file;
}

static MENU_UPDATE_FUNC(viewfile_show)
{
    if (view_file)
    {
        static char buf[1025];
        FILE * file = FIO_Open( gPath, O_RDONLY | O_SYNC );
        if (file != INVALID_PTR)
        {
            int r = FIO_ReadFile(file, buf, sizeof(buf)-1);
            FIO_CloseFile(file);
            buf[r] = 0;
            info->custom_drawing = CUSTOM_DRAW_THIS_MENU;
            clrscr();
            big_bmp_printf(FONT_MED, 0, 0, "%s", buf);
        }
        else
        {
            MENU_SET_WARNING(MENU_WARN_ADVICE, "Error reading %s", gPath);
            view_file = 0;
        }
    }
    else
    {
        update_action(entry, info);
    }
}

static int delete_confirm_flag = 0;

static MENU_SELECT_FUNC(delete_file)
{
    if (streq(gPath+1, ":/AUTOEXEC.BIN"))
    {
        beep();
        return;
    }

    if (!delete_confirm_flag)
    {
        delete_confirm_flag = get_ms_clock_value();
        beep();
    }
    else
    {
        delete_confirm_flag = 0;
        FIO_RemoveFile(gPath);
        BrowseUp();
    }
}

static MENU_UPDATE_FUNC(delete_confirm)
{
    update_action(entry, info);

    /* delete confirmation timeout after 2 seconds */
    if (get_ms_clock_value() > delete_confirm_flag + 2000)
        delete_confirm_flag = 0;

    /* no question mark in in our font, fsck! */
    if (delete_confirm_flag)
        MENU_SET_RINFO("Press SET to confirm");
}

static MENU_SELECT_FUNC(select_file)
{
    struct file_entry * fe = (struct file_entry *) priv;

    /* fe will be freed in clear_file_menu; backup things that we are going to reuse */
    char name[MAX_PATH_LEN];
    snprintf(name, sizeof(name), "%s", fe->name);
    int size = fe->size;
    STR_APPEND(gPath, "%s", name);

    clear_file_menu();
    /* at this point, fe was freed and is no longer valid */
    fe = 0;

    struct file_entry * e = add_file_entry(name, TYPE_FILE, size);
    if (!e) return;
    e->menu_entry.select = BrowseUpMenu;
    e->menu_entry.select_Q = BrowseUpMenu;
    e->menu_entry.priv = e;

    e = add_file_entry("Copy", TYPE_ACTION, 0);
    e->menu_entry.select = CopyFile;
    e->menu_entry.update = CopyFileProgress;

    e = add_file_entry("Move", TYPE_ACTION, 0);
    e->menu_entry.select = MoveFile;
    e->menu_entry.update = MoveFileProgress;

    e = add_file_entry("View", TYPE_ACTION, 0);
    e->menu_entry.select = viewfile_toggle;
    e->menu_entry.update = viewfile_show;

    e = add_file_entry("Delete", TYPE_ACTION, 0);
    e->menu_entry.select = delete_file;
    e->menu_entry.update = delete_confirm;

    //~ e = add_file_entry("Copy", TYPE_ACTION, 0);
    //~ e = add_file_entry("Rename", TYPE_ACTION, 0);

    build_file_menu();
}

static MENU_UPDATE_FUNC(update_file)
{
    struct file_entry * fe = (struct file_entry *) entry->priv;
    MENU_SET_VALUE("");

    MENU_SET_RINFO("%s", format_size(fe->size));
    MENU_SET_ICON(MNI_OFF, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static MENU_SELECT_FUNC(default_select_action)
{
    beep();
}

static MENU_UPDATE_FUNC(update_action)
{
    MENU_SET_VALUE("");
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static int InitRootDir()
{
    cf_present = is_dir("A:/");
    sd_present = is_dir("B:/");

    if (cf_present && !sd_present)
    {
        Browse("A:/");
    }
    else if (sd_present && !cf_present)
    {
        Browse("B:/");
    }
    else if (sd_present && cf_present)
    {
        Browse("");
    }
    else return -1;

    return 0;
}

unsigned int fileman_init()
{
    menu_add("Debug", fileman_menu, COUNT(fileman_menu));
    op_mode = FILE_OP_NONE;
    InitRootDir();
    return 0;
}

unsigned int fileman_deinit()
{
    return 0;
}


MODULE_INFO_START()
    MODULE_INIT(fileman_init)
    MODULE_DEINIT(fileman_deinit)
MODULE_INFO_END()

MODULE_STRINGS_START()
    MODULE_STRING("Author", "ML dev.")
    MODULE_STRING("License", "GPL")
    MODULE_STRING("Description", "File browser")
MODULE_STRINGS_END()
#25
It's already done , but I would like to collect testers for implove this module.

I just added copy and move codes for A1ex refucterd code.
If you have compile environment, please test it with Non-important SD card for Testing


diff -r de0bcff3619c modules/file_man/file_man.c
--- a/modules/file_man/file_man.c       Sat Jun 01 02:08:29 2013 +0300
+++ b/modules/file_man/file_man.c       Sat Jun 01 16:57:08 2013 +0900
@@ -8,6 +8,8 @@

#define MAX_PATH_LEN 0x80
static char gPath[MAX_PATH_LEN];
+static char gSrcFile[MAX_PATH_LEN];
+static unsigned int op_mode;

static int cf_present;
static int sd_present;
@@ -26,6 +28,13 @@
#define TYPE_FILE 1
#define TYPE_ACTION 2

+enum _FILER_OP {
+    FILE_OP_NONE,
+    FILE_OP_COPY,
+    FILE_OP_MOVE,
+    FILE_OP_PREVIEW
+};
+
static struct file_entry * file_entries = 0;

/* view file mode */
@@ -144,6 +153,26 @@
         return;
     }

+    if(op_mode != FILE_OP_NONE)
+    {
+        console_printf("ScanDir\n");
+        char srcpath[MAX_PATH_LEN];
+        strcpy(srcpath,gSrcFile);
+        char *p = srcpath+strlen(srcpath);
+        while (p > srcpath && *p != '/') p--;
+        *(p+1) = 0;
+
+        console_printf("src: %s\n",srcpath);
+        console_printf("dst: %s\n",path);
+
+
+        if(strcmp(path,srcpath) != 0){
+            add_file_entry("***Select Here***", TYPE_DIR, 0);
+            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
+        }
+    }
+
+
     add_file_entry("../", TYPE_DIR, 0);

     struct fio_file file;
@@ -230,6 +259,100 @@
     }
}

+static int
+ML_FIO_CopyFile(char *src,char *dst){
+    const int bufsize = 128*1024;
+    void* buf = alloc_dma_memory(bufsize);
+    if (!buf) return 1;
+
+    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
+    if (f == INVALID_PTR) return 1;
+
+    FILE* g = FIO_CreateFile(dst);
+    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }
+
+    int r = 0;
+    while ((r = FIO_ReadFile(f, buf, bufsize)))
+        FIO_WriteFile(g, buf, r);
+
+    FIO_CloseFile(f);
+    FIO_CloseFile(g);
+    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
+    free_dma_memory(buf);
+    return 0;
+}
+
+static int
+ML_FIO_MoveFile(char *src,char *dst){
+
+    ML_FIO_CopyFile(src,dst);
+    FIO_RemoveFile(src);
+    return 0;
+}
+
+static void
+FileCopy(void *unused)
+{
+    char fname[MAX_PATH_LEN];
+    size_t totallen = strlen(gSrcFile);
+    char *p = gSrcFile + totallen;
+    while (p > gSrcFile && *p != '/') p--;
+    strcpy(fname,p+1);
+
+    char dstfile[MAX_PATH_LEN];
+    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);
+
+    console_printf("Copy\n");
+    console_printf("src: %s\n",gSrcFile);
+    console_printf("dst: %s\n",dstfile);
+    ML_FIO_CopyFile(gSrcFile,dstfile);
+
+}
+
+static void
+FileMove(void *unused)
+{
+    char fname[MAX_PATH_LEN];
+    size_t totallen = strlen(gSrcFile);
+    char *p = gSrcFile + totallen;
+    while (p > gSrcFile && *p != '/') p--;
+    strcpy(fname,p+1);
+
+    char dstfile[MAX_PATH_LEN];
+    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);
+
+    console_printf("Move\n");
+    console_printf("src: %s\n",gSrcFile);
+    console_printf("dst: %s\n",dstfile);
+    ML_FIO_MoveFile(gSrcFile,dstfile);
+
+}
+
+
+static void FileOperation(){
+
+    switch(op_mode){
+    case FILE_OP_COPY:
+        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
+        break;
+    case FILE_OP_MOVE:
+        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
+        break;
+    case FILE_OP_PREVIEW:
+        break;
+    }
+    //cleanup
+    op_mode = FILE_OP_NONE;
+
+    ScanDir(gPath);
+}
+
+static void FileOpCancel(){
+    gSrcFile[0] = 0;
+    op_mode = FILE_OP_NONE;
+    ScanDir(gPath);
+}
+
static MENU_SELECT_FUNC(BrowseUpMenu)
{
     BrowseUp();
@@ -239,18 +362,18 @@
{
     struct file_entry * fe = (struct file_entry *) priv;
     char* name = (char*) fe->name;
-    if ((name[0] == '.' &&
-         name[1] == '.' &&
-         name[2] == '/')
-         || (delta < 0)
-        )
-    {
-       BrowseUp();
-    }
+    if(!strcmp(name,"***Select Here***")){
+        FileOperation();
+    }else if(!strcmp(name,"*** Cancel OP ***")){
+        FileOpCancel();
+    }else if (!strcmp(name,"../") || (delta < 0))
+        {
+            BrowseUp();
+        }
     else
-    {
-       BrowseDown(name);
-    }
+        {
+            BrowseDown(name);
+        }
}

static MENU_UPDATE_FUNC(update_dir)
@@ -288,6 +411,30 @@
     return str;
}

+static MENU_SELECT_FUNC(CopyFile)
+{
+    strcpy(gSrcFile,gPath);
+    console_printf("Copysrc: %s\n",gSrcFile);
+    op_mode = FILE_OP_COPY;
+}
+
+static MENU_UPDATE_FUNC(CopyFileProgress)
+{
+
+}
+
+static MENU_SELECT_FUNC(MoveFile)
+{
+    strcpy(gSrcFile,gPath);
+    console_printf("Movesrc: %s\n",gSrcFile);
+    op_mode = FILE_OP_MOVE;
+}
+
+static MENU_UPDATE_FUNC(MoveFileProgress)
+{
+
+}
+
static MENU_SELECT_FUNC(viewfile_toggle)
{
     view_file = !view_file;
@@ -375,6 +522,14 @@
     e->menu_entry.select = BrowseUpMenu;
     e->menu_entry.select_Q = BrowseUpMenu;
     e->menu_entry.priv = e;
+
+    e = add_file_entry("Copy", TYPE_ACTION, 0);
+    e->menu_entry.select = CopyFile;
+    e->menu_entry.update = CopyFileProgress;
+
+    e = add_file_entry("Move", TYPE_ACTION, 0);
+    e->menu_entry.select = MoveFile;
+    e->menu_entry.update = MoveFileProgress;

     e = add_file_entry("View", TYPE_ACTION, 0);
     e->menu_entry.select = viewfile_toggle;
@@ -438,6 +593,7 @@
unsigned int fileman_init()
{
     menu_add("Debug", fileman_menu, COUNT(fileman_menu));
+    op_mode = FILE_OP_NONE;
     InitRootDir();
     return 0;
}