#include "../include/xcv_license.h" //PCH #ifdef _WIN32 #include //PCH conflicts with wx/msw/missing.h #include //PathIsRelative #pragma comment(lib,"Shlwapi.lib") #elif defined(__GNUC__) #include #include #include #include #endif namespace Widgets95 {//-. //<-' void ui::filesys::_update_area() { bi::_update_area(); assert(!_box_behavior); if(_list) { if(this!=_list->associated_object) { _list = nullptr; return; } int dh = _h; assert(this==_list->parent()); //int dw = _w-_list->parent()->_w; bool expand = !_alignment; int dw = expand?_w:0; inset_dims(&dw,&dh); if(expand) _list->_w = dw; else _list->_w+=dw; _list->_h = dh; _list->update_area(); } } static void xcv_filebrower_dir_list_callback(ui::listbox *_list) { ui::filesys *my = dynamic_cast(_list->associated_object); if(!my){ assert(0); return; } /* file or directory selected */ const char *selected = _list->c_str(); if(*selected=='/'/*||selected[0]=='\\'*/) { //2019: I'm changing this so that something happens when clicking //on directories, since there is no recourse. /* if(my->click_chdir) my->chdir(selected+1); */ my->lsdir(selected+1,my->_click_chdir); } else if(*selected) { my->_file = true; //my->_file = selected; my->execute_callback(); } } /****************************** WIDGETS_95_FileBrowser::WIDGETS_95_FileBrowser() **********/ ui::listbox *ui::filesys::_list_init(listbox *l) { if(_list&&l!=_list) _list->_delete(); if(l) //l = new listbox(this,true,1); { //_scrollbar_init creates a panel to contain the _list and its //scrollbar... in this case it could probably use this as its //panel? //assert(this==l->parent()); l->_id = 1; l->set_object_callback(xcv_filebrower_dir_list_callback,this); l->set_click(double_click); //Getting margins may be unnecessary. bi::_update_area(); //scrollbar_int may be necessary. l->update_area(); offset_dims(&(_w=l->_w),&(_h=l->_h)); } return _list = l; } /****************************** WIDGETS_95_FileBrowser::fbreaddir() **********/ bool ui::filesys::lsdir(c_string d, bool chdir) { enum{ globN=260 }; //MAX_PATH char glob[globN+2]; int n = 0; const char *text = _text.c_str(); bool rel,cde = !*text; if(d.str) { rel = *d.str!='/'; #ifdef _WIN32 rel = PathIsRelativeA(d.str); #endif } else rel = true; if(cde) _text.assign(".",1); if(chdir) { const char *cd = d.str; if(rel&&!cde) { //Mixing lsdir and chdir? if(!cd||!*cd) cd = "."; sprintf(glob,"%s/%s",text,cd); cd = glob; } if(cd&&*cd/*&&strcmp(cd,".")*/) { #ifdef _WIN32 if(!SetCurrentDirectoryA(cd)) #elif defined(__GNUC__) if(::chdir(cd)) #endif return false; } n = 1; *glob = '.'; } else if(!d.empty()) { //2019: Delivering browsing without changing. if(*d.str=='.') switch(d.str[1]) //Special case? { case '\0': goto relist; //. case '.': if(d.str[2]) break; //.. //Remove directory unless it's a . or .. pattern. if(const char*sep=strrchr(text,'/')) if(strcmp("..",sep+1)) { _text.erase(sep-text); goto relist; //HACK } } if(rel) n = snprintf(glob,globN,"%s/%s",text,d.str); else relist2: memcpy(glob,d.str,n=std::min(globN,strlen(d.str))); } else relist: { d.str = _text.c_str(); goto relist2; } if(cde) _text.clear(); listbox::item *i,*di = nullptr; #if defined(_WIN32) WIN32_FIND_DATAA FN; HANDLE hFind; memcpy(glob+n,"/*",3); hFind = FindFirstFileA(glob,&FN); glob[n] = '\0'; if(hFind==INVALID_HANDLE_VALUE) goto error; if(_list) { _list->delete_all(); do { i = new listbox::item; int len = strlen(FN.cFileName); if(FN.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { i->_text.append("/",1); //'\\'; _list->insert_item(i,di,behind); di = i; } else _list->add_item(i); i->_text.append(FN.cFileName); }while(FindNextFileA(hFind,&FN)); } if(GetLastError()==ERROR_NO_MORE_FILES) { FindClose(hFind); } else error: { perror("fbreaddir"); return false; } #elif defined(__GNUC__) glob[n] = '\0'; DIR *dir = opendir(glob); if(!dir) { perror("fbreaddir"); return false; } else if(_list) { _list->delete_all(); int cat = globN-n; glob[n] = '/'; struct dirent *dirp; while(dirp=readdir(dir)) /* open directory */ { i = new listbox::item; struct stat dr; /* dir is directory */ strncpy(glob+n+1,dirp->d_name,cat); if(!lstat(glob,&dr)&&S_ISDIR(dr.st_mode)) { i->_text.append("/",1); _list->insert_item(i,di,behind); di = i; } else _list->add_item(i); i->_text.append(dirp->d_name); } glob[n] = '\0'; } closedir(dir); #endif if(_list) { //Historically filesys assumed id matched current_line. i = _list->first_item(); for(int id=0;i;i=i->next()) i->_id = id++; //back-compat } //2019: Why not update this member? And clear file, as in directory. _text.assign(glob); _file = false; //_file.clear(); _current_dir = chdir; if(chdir?_chdir_cb:_lsdir_cb) execute_callback(); return true; } //---. }//<-'