#include #include #include #include #include #include #include #include #include #include #include "ml.h" #include "kbd_keys.h" #define FNAME_LEN 14 static char ESC_STR[]={_ESC,0}; fch_wndclass_t STD_fchclass={ SIMPLE_BORDER,MK_COL(BLACK,LIGHTGRAY),MK_COL(BLACK,LIGHTGRAY), MK_COL(WHITE,MAGENTA), 10,10,70,20,0, ESC_STR,"", NULL, NULL }; static int mask_valid(void *p) { char *str=(char *)p,dir[65],drive[3],buf[65]; struct ffblk sr; fnsplit(str,drive,dir,buf,buf); fnmerge(buf,drive,dir,"*",".*"); errno=0; findfirst(buf,&sr,FA_DIREC); return errno == 0; } static int lessthan(char *str1, char *str2) { if(!strcmp(substr(str1,3),"..\\")) return 0; if(!strcmp(str2,"..\\")) return 1; return strcmp(str1,str2) < 0; } static void insert_name(char *name, int n, char *space) { int i,k; char *start,*p; for(i=0; i < n && lessthan(space+i*FNAME_LEN,name); ) i++; start=space+i*FNAME_LEN; for(p=space+(n+1)*FNAME_LEN-1; p >= start+FNAME_LEN ; p--) *p=*(p-FNAME_LEN); strcpy(start,name); for(k=strlen(name),p=start+k; k < FNAME_LEN-1; k++) *p++=' '; *p='\0'; } static void set_fields(menu_item_t *items, char *space, int n, int width, int act, int pas) { int i,per_str; menu_item_t *it; per_str=width/FNAME_LEN; for(i=0; i < n; i++) { it=items+i; it->s=space+i*FNAME_LEN; it->comment=""; it->edf=NULL; it->act_col=act; it->pas_col=pas; it->menx=(i % per_str)*(FNAME_LEN+1); it->meny=i/per_str; it->disabled_col=BLACK; it->enabled_now=1; it->retcode=128+i; it->hotkeys="";it->hotkeys0=""; } } static int make_items(char *mask, menu_item_t **items, char **strings, int width /* ширина окна */, int act, int pas) { struct ffblk sr; int i,nfiles,n; char buf[FNAME_LEN+3],drive[4],dir[65],name[9],ext[4],full_mask[80]; char *errnomemory="not enough memory"; fnsplit(mask,drive,dir,name,ext); fnmerge(full_mask,drive,dir,"*",".*"); errno=0; findfirst(full_mask,&sr,FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_DIREC | FA_ARCH); for(nfiles=0; errno==0; nfiles++) findnext(&sr); if((*items=calloc(nfiles,sizeof(menu_item_t)))==NULL ||(*strings=calloc(nfiles,FNAME_LEN))==NULL) error(errnomemory); errno=0; findfirst(mask,&sr,FA_ARCH); for(n=0; errno==0; n++) { /* Набираем имена файлов */ strlwr(sr.ff_name); insert_name(sr.ff_name,n,*strings); findnext(&sr); } errno=0; findfirst(full_mask,&sr,FA_DIREC); for(i=0; errno==0; ) { /* Набираем имена подкаталогов */ if(sr.ff_attrib & FA_DIREC) { if(strcmp(sr.ff_name,".")){ strcat(strcpy(buf,sr.ff_name),"\\"); insert_name(buf,i,*strings+n*FNAME_LEN); i++; } } findnext(&sr); } set_fields(*items,*strings,i+n,width,act,pas); return i+n; } static int is_subdir(char *str) { int i=strlen(str)-1; for(; str[i]==' ' && i >= 0; i--); if(i < 0) return 0; return str[i]=='\\'; } static int del_dir(char *dir) { char *p=dir+strlen(dir)-2; int b=0; for(; p >= dir && *p != '\\'; ) { *p--='\0'; b=1; } return b; } static void cut_spaces(char *dir) { char *p=dir+strlen(dir)-1; for(; p > dir && *p == ' '; p--) *p='\0'; } static int mygetdrive(char *dr) { if(*dr=='\0') return 0; else return tolower(*dr)-'a'+1; } static void add_MR(char *s) { int l; l=strlen(s); if(s[l-1]!=CH_MOUSERELEASE || l==0) { s[l]=CH_MOUSERELEASE; s[l+1]='\0'; } /* Приписали к концу CH_MOUSERELEASE */ } static void delete_MR(char *s) { int l; l=strlen(s); if(s[l-1]==CH_MOUSERELEASE && l) { s[l-1]='\0'; } /* Убрали CH_MOUSERELEASE */ } #define WAS_ENTER(ch) (128 <= (ch) && (ch) <= 128+nfiles) ml_retcode_t get_fname_rmenu( struct fchk_wc *wc, char *up_name, char *down_name, char *mask, char *filename, void *show_par, void *choose_par) { menu_t in_mask_mnu,chfile_mnu,right_menu; window_t *cur_win,*old_win=getcurwin(); window_t wnd,file_wnd,right_wnd; int rmenu_exist,i,lmenu_width,nfiles,new_show_files,win_width; char lhk[80], /* _TAB+hk */ lhk0[80], /* _END+_HOME+CH_MOUSEBUTTON+hk0 } */ lhk0_MR[80], /* CH_MOUSERELEASE, _END+_HOME+CH_MOUSEBUTTON+hk0 } */ lhk_mask[80]; /* _ENTER+_TAB+hk */ ml_retcode_t ch; char *file_item_strings=NULL; enum { MASK, FILES, REDRAW_LEFT, RIGHT_MENU } cur_menu; char drive[4],dir[85],name[9],ext[5]; string buf; edit_field_t mask_edf={ 0,0,-1 /* определю потом */, MK_COL(WHITE,MAGENTA),MK_COL(LIGHTGRAY,MAGENTA), "",STRING,NULL,NULL,NULL,mask_valid }; menu_item_t mask_item={ "","",NULL,0,0,BLACK,LIGHTGREEN,0,1,1,NULL,NULL }, *file_items=NULL; lhk[0]=_TAB; strcpy(lhk+1,wc->hk); lhk_mask[0]=_ENTER; lhk_mask[1]=_TAB; strcpy(lhk_mask+2,wc->hk); lhk0[0]=_END; lhk0[1]=_HOME; lhk0[2]=CH_MOUSEBUTTON; strcpy(lhk0+3,wc->hk0); strcpy(lhk0_MR,lhk0); mask_edf.hk=lhk_mask; mask_edf.hk0=lhk0; mask_edf.variable=mask; mask_item.edf=&mask_edf; mask_item.hotkeys=lhk_mask; mask_item.hotkeys0=wc->hk0; rmenu_exist = (wc->right_menu_width > 0) && (wc->show_right_menu != NULL) && (wc->choose_right != NULL); show_window(&wnd,wc->x1,wc->y1,wc->x2,wc->y2, wc->string_col,wc->border_col, wc->border,up_name,down_name); cur_win=&wnd; win_width=wnd.x2-wnd.x1; lmenu_width=win_width-wc->right_menu_width; if(lmenu_width <= FNAME_LEN) error("Неверно задана ширина правого окна"); mask_edf.maxlen=win_width; fillchar(buf,win_width,196); winfwritexy(0,1,wc->border_col,buf); if(rmenu_exist) { buf[0]=179; buf[1]='\0'; for(i=2; i <= wnd.y2-wnd.y1; i++) { /* buf[0]= i==1 ? 180 : 179; */ winfwritexy(lmenu_width,i,wc->border_col,buf); } show_window_bar(&right_wnd, cur_win->x1+lmenu_width+1,cur_win->y1+2, cur_win->x2, cur_win->y2, wc->string_col,BLACK,NO_BORDER,"",""); (*wc->show_right_menu)(&right_menu,show_par,wc); } set_active_window(&wnd); if(!mask_valid(mask)) { beep(); strcpy(mask,"*.*"); } show_menu(&in_mask_mnu,0,0,0,0,0,&mask_item,1,lhk_mask,lhk0); set_menu_mode(&in_mask_mnu,ML_NOMOUSEEXTESC); cur_win=getcurwin(); show_window_bar(&file_wnd,cur_win->x1,cur_win->y1+2, cur_win->x1+lmenu_width,cur_win->y2, wc->string_col,BLACK,NO_BORDER,"",""); cur_menu=FILES; new_show_files=1; do { fnsplit(mask,drive,dir,name,ext); switch(cur_menu){ case MASK: set_active_window(&wnd); check_field_changed(); /* Сбрасываем */ ch=choose_from_menu(&in_mask_mnu); if(ch==_ENTER || ch==_TAB) { cur_menu=FILES; ch=0; } /* Изменили ли маску */ new_show_files=check_field_changed(); break; case FILES: case REDRAW_LEFT: set_active_window(&file_wnd); do{ if(new_show_files){ if(file_items) { free(file_items); free(file_item_strings); file_items=NULL; file_item_strings=NULL; } clear_window(); nfiles=make_items(mask,&file_items,&file_item_strings, lmenu_width,wc->file_col,wc->string_col); add_MR(lhk0_MR); show_menu(&chfile_mnu,0,0,0,0,0,file_items,nfiles,lhk,lhk0_MR); set_menu_mode(&chfile_mnu, ML_4DIRECT | ML_NOLOOPS | ML_NOMOUSEEXTESC); new_show_files=0; } else delete_MR(lhk0_MR); if(cur_menu==REDRAW_LEFT) ch=_TAB; /* переходим снова в правое меню */ else ch=choose_from_menu(&chfile_mnu); strcpy(buf,file_items[chfile_mnu.cur_item].s); cut_spaces(buf); if(ch==_TAB) { if(rmenu_exist) cur_menu=RIGHT_MENU; else cur_menu=MASK; } if(!is_subdir(buf)){ fnmerge(filename,drive,dir,buf,""); if(WAS_ENTER(ch)) ch=_ENTER; } else { fnsplit(mask,drive,dir,name,ext); if(WAS_ENTER(ch)) { if(strcmp(buf,"..\\")) strcat(dir,buf); else if(!del_dir(dir)) { dir[0]='\\'; getcurdir(mygetdrive(drive),dir+1); del_dir(dir); } new_show_files=1; } fnmerge(mask,drive,dir,name,ext); strcpy(filename,buf); } } while(new_show_files && ch==_ENTER); break; case RIGHT_MENU: set_active_window(&right_wnd); ch=(*wc->choose_right)(&right_menu,choose_par,wc); if(ch==_TAB) cur_menu=MASK; else if(ch == CH_REDRAW_LEFT) cur_menu=REDRAW_LEFT; new_show_files=1; } if(ch==RC_MOUSEBUTTON) { if(mouse_in_menu(&wnd,NULL,FALSE)==-1) ch=_ESC; else if(mouse_in_menu(&file_wnd,NULL,FALSE) != -1) { cur_menu=FILES; /* if((i=mouse_in_menu(&file_wnd,&chfile_mnu,FALSE)) != -1) set_item(&chfile_mnu,i); */ ch=0; } else if(mouse_in_menu(&wnd,&in_mask_mnu,FALSE) != -1) { cur_menu=MASK; ch=0; } else if(rmenu_exist) { if(mouse_in_menu(&right_wnd,NULL,FALSE) != -1) { cur_menu=RIGHT_MENU; ch=0; } } } } while(!in_str(ch,wc->hk) && !in_str(GETK0(ch),wc->hk0) && ch != _ENTER); if(file_items) { free(file_items); free(file_item_strings); } erase_window(&file_wnd); if(rmenu_exist) erase_window(&right_wnd); erase_window(&wnd); set_active_window(old_win); return ch; } char *getfilename(char *mask, char *name) { ml_retcode_t ch; ch=get_fname_rmenu(&STD_fchclass," File "," Name ",mask,name,NULL,NULL); if(ch!=_ENTER) strcpy(name,""); return name; }