Window IO.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. Here FSTD_LINK is used for folders used as files.
  6. /******************************************************************************/
  7. #define QPS_DATA "Data"
  8. #define QPS_DESKTOP "Desktop"
  9. #define QPS_ONEDRIVE "OneDrive"
  10. #define QPS_FAVORITES "Favorites:"
  11. #define QPS_RECENT "Recent:"
  12. #define QPS_ADD_FAVORITE "Add to Favorites"
  13. #define QPS_REM_FAVORITE "Remove from Favorites"
  14. #define QPS_MAX_RECENT 8
  15. /******************************************************************************/
  16. static Str FileSize(C WindowIO::File &f)
  17. {
  18. switch(f.type)
  19. {
  20. case FSTD_FILE: return TextInt((f.size+1023)>>10, -1, 3)+" KB";
  21. case FSTD_LINK: return "Unknown";
  22. default : return S;
  23. }
  24. }
  25. static MemberDesc win_io_file_size_sort(MEMBER(WindowIO::File, size));
  26. Memc<Str> WindowIOFavorites, WindowIORecents;
  27. /******************************************************************************/
  28. void WindowIORecent(Str path)
  29. {
  30. if(path.is())REPA(WindowIORecents)if(EqualPath(WindowIORecents[i], path))
  31. {
  32. REPD(j, i)Swap(WindowIORecents[j], WindowIORecents[j+1]); // move to 1st position
  33. return;
  34. }
  35. WindowIORecents.NewAt(0)=path;
  36. WindowIORecents.setNum(Min(QPS_MAX_RECENT, WindowIORecents.elms())); // limit amount of elements
  37. }
  38. /******************************************************************************/
  39. static void ChangedText (WindowIO &wio) {wio.setBar ();}
  40. static void OK (WindowIO &wio) {wio.Ok ();}
  41. static void Cancel (WindowIO &wio) {wio.hide ();}
  42. static void CreateDir (WindowIO &wio) {wio.createDir ();}
  43. static void Up (WindowIO &wio) {wio.back ();}
  44. static void Rename (WindowIO &wio) {wio.renameDo ();}
  45. static void RemoveAsk (WindowIO &wio) {wio.removeAsk ();}
  46. static void RemoveDo (WindowIO &wio) {wio.removeDo ();}
  47. static void RemoveCancel (WindowIO &wio) {wio.removeCancel ();}
  48. static void OverwriteDo (WindowIO &wio) {wio.overwriteDo ();}
  49. static void OverwriteCancel(WindowIO &wio) {wio.overwriteCancel();}
  50. static void Explore (WindowIO &wio) {wio.exploreDo ();}
  51. /******************************************************************************/
  52. // QUICK PATH SELECTOR
  53. /******************************************************************************/
  54. #if IOS // on iOS we can only write to "SystemPath(SP_APP_DATA)"
  55. static Str QPSShortPath(C Str &path) {return SkipStartPath(path, SystemPath(SP_APP_DATA));}
  56. static Str QPSFullPath (C Str &path) {return (path.is() && !FullPath(path)) ? SystemPath(SP_APP_DATA).tailSlash(true)+path : path;}
  57. #else
  58. static Str QPSShortPath(C Str &path) {return SkipStartPath(path, DataPath());}
  59. static Str QPSFullPath (C Str &path) {return (path.is() && !FullPath(path)) ? DataPath()+path : path;}
  60. #endif
  61. static void PathChanged(C Str &path, QuickPathSelector &qps)
  62. {
  63. if(path.is())
  64. {
  65. if(path==QPS_DATA )qps.setPath(DataPath());else
  66. if(path==QPS_DESKTOP )qps.setPath(SystemPath(SP_DESKTOP ));else
  67. if(path==QPS_ONEDRIVE )qps.setPath(SystemPath(SP_ONE_DRIVE));else
  68. if(path==QPS_ADD_FAVORITE)
  69. {
  70. Str path=qps.getPath(); if(path.is())
  71. {
  72. if(!QPSShortPath(path).is())return;
  73. REPA(WindowIOFavorites)if(EqualPath(WindowIOFavorites[i], path))return;
  74. WindowIOFavorites.add(path);
  75. }
  76. }else
  77. if(path==QPS_REM_FAVORITE)
  78. {
  79. Str path=qps.getPath(); if(path.is())
  80. {
  81. REPA(WindowIOFavorites)if(EqualPath(WindowIOFavorites[i], path))WindowIOFavorites.remove(i, true);
  82. }
  83. }else
  84. if(path!=QPS_FAVORITES && path!=QPS_RECENT)qps.setPath(QPSFullPath(path)); // custom path
  85. }
  86. }
  87. static void QPSChangedButton(QuickPathSelector &qps)
  88. {
  89. if(qps.Button::operator()())qps.setData(); // set most recent data
  90. if(qps._func)qps._func(&qps); // call stored callback
  91. }
  92. ComboBox& QuickPathSelector::create()
  93. {
  94. super::create();
  95. menu_align=-1;
  96. _func =Button::_func; // store previous copy of the button function
  97. Button::func(QPSChangedButton, T);
  98. return T;
  99. }
  100. void QuickPathSelector::setData()
  101. {
  102. Node<MenuElm> n;
  103. {
  104. if( DataPath( ).is())n+=QPS_DATA;
  105. if(SystemPath(SP_DESKTOP ).is())n+=QPS_DESKTOP;
  106. if(SystemPath(SP_ONE_DRIVE).is())n+=QPS_ONEDRIVE;
  107. Bool header=false;
  108. FREPA(WindowIOFavorites)
  109. {
  110. Str p=QPSShortPath(WindowIOFavorites[i]);
  111. if( p.is())
  112. {
  113. if(!header){header=true; if(n.children.elms())n++; Node<MenuElm> &c=(n+=QPS_FAVORITES); c.flag(MENU_NOT_SELECTABLE);}
  114. n+=p;
  115. }
  116. }
  117. header=false;
  118. FREPA(WindowIORecents)
  119. {
  120. Str p=QPSShortPath(WindowIORecents[i]);
  121. if( p.is())
  122. {
  123. if(!header){header=true; if(n.children.elms())n++; Node<MenuElm> &c=(n+=QPS_RECENT); c.flag(MENU_NOT_SELECTABLE);}
  124. n+=p;
  125. }
  126. }
  127. if(n.children.elms())n++;
  128. n+=QPS_ADD_FAVORITE;
  129. n+=QPS_REM_FAVORITE;
  130. }
  131. super::setData(n).menu.func(PathChanged, T);
  132. }
  133. WindowIO::QPS::QPS(WindowIO &win_io) : win_io(win_io) {}
  134. Str WindowIO::QPS::getPath( ) {return win_io.path()+win_io.subPath();}
  135. void WindowIO::QPS::setPath(C Str &path) {win_io.path(S, path); win_io.getList();}
  136. /******************************************************************************/
  137. // WINDOW IO
  138. /******************************************************************************/
  139. void WindowIO::zero()
  140. {
  141. path_mode=WIN_IO_PM_FULL;
  142. ext_mode=WIN_IO_EXT_ALWAYS;
  143. _border=0.06f;
  144. _mode=WIN_IO_LOAD;
  145. _dir_operate=false;
  146. _func_user=null;
  147. _load=null;
  148. _save=null;
  149. }
  150. WindowIO::WindowIO() : quick(T) {zero();}
  151. WindowIO& WindowIO::del()
  152. {
  153. rename_window.del();
  154. remove_window.del();
  155. overwrite_window.del();
  156. _ext.del();
  157. _ext_desc.del();
  158. _dot_exts.del();
  159. _path.del();
  160. _sub_path.del();
  161. _op_name.del();
  162. file.del();
  163. super::del(); zero(); return T;
  164. }
  165. WindowIO& WindowIO::create(C Str &ext, C Str &path, C Str &sub_path, void (*load)(C Str &name, Ptr user), void (*save)(C Str &name, Ptr user), Ptr user)
  166. {
  167. del();
  168. ListColumn win_io_file_column[]=
  169. {
  170. ListColumn(MEMBER(WindowIO::File, name), 0.00f, MLTC(u"Name", PL,u"Nazwa" )), // 0
  171. ListColumn(FileSize , 0.29f, MLTC(u"Size", PL,u"Rozmiar")), // 1
  172. };
  173. win_io_file_column[1].sort=&win_io_file_size_sort;
  174. Gui +=super ::create().hide(); button[2].show(); flag|=WIN_RESIZABLE;
  175. T +=region .create();
  176. T +=textline .create().func(ChangedText, T).desc(MLTC(u"Name", PL,u"Nazwa"));
  177. T +=ok .create(MLTC(u"OK" , PL,u"OK" )).func(OK , T);
  178. T +=cancel .create(MLTC(u"Cancel" , PL,u"Anuluj" )).func(Cancel , T);
  179. T +=create_dir.create(MLTC(u"Create Directory", PL,u"Utwórz Katalog")).func(CreateDir, T).desc(MLTC(u"Create Directory using name specified above", PL,u"Utwórz Katalog na podstawie podanej nazwy"));
  180. T +=up .create(MLTC(u"Up" , PL,u"Wstecz" )).func(Up , T);
  181. T +=rename .create(MLTC(u"Rename" , PL,u"Zmień Nazwę" )).func(Rename , T).desc(MLTC(u"Rename (F2)", PL,u"Zmień nazwę (F2)"));
  182. T +=remove .create(MLTC(u"Delete" , PL,u"Usuń" )).func(RemoveAsk, T).desc(MLTC(u"Move to Recycle Bin (Del)", PL,u"Przenieś do kosza (Del)"));
  183. #if DESKTOP
  184. T +=explore .create(MLTC(u"Explore" , PL,u"Eksploruj" )).func(Explore , T).desc(MLTC(u"Open in Windows Explorer (F4)", PL,u"Otwórz w Eksploratorze Windows (F4)"));
  185. #endif
  186. T +=quick .create( ).desc("Quick select path by using Favorites");
  187. region+=list .create(win_io_file_column, Elms(win_io_file_column)).setElmType(MEMBER(WindowIO::File, type)); list.sort_column[0]=0; list.flag|=LIST_TYPE_SORT|LIST_SCALABLE; list.cur_mode=LCM_ALWAYS; list.zoom_min=1/1.2f; list.zoom_max=1.2f;
  188. Node<MenuElm> node; T+=menu.create(node).hide();
  189. Gui+=rename_window.create().level(1).rect(Rect_C(0, 0, 1.2f, 0.14f)).hide(); rename_window.button[2].show();
  190. rename_window+=rename_textline.create(Rect_LU(0, 0, rename_window.clientWidth(), rename_window.clientHeight()).extend(-0.01f));
  191. Gui+=remove_window.create().level(1).rect(Rect_C(0, 0, 1.0f, 0.4f)).hide();
  192. remove_window+=remove_text.create(Vec2 (remove_window.clientWidth()*0.50f, -0.1f), MLTC(u"Are you sure you wish to recycle selected item?", PL,u"Czy jesteś pewien że chcesz przenieść\nwybrany element do kosza?"));
  193. remove_window+=remove_yes .create(Rect_C(remove_window.clientWidth()*0.25f, -0.25f, 0.28f, 0.07f), MLTC(u"Yes", PL,u"Tak")).func(RemoveDo , T);
  194. remove_window+=remove_no .create(Rect_C(remove_window.clientWidth()*0.75f, -0.25f, 0.28f, 0.07f), MLTC(u"No" , PL,u"Nie")).func(RemoveCancel, T);
  195. Gui+=overwrite_window.create().level(1).rect(Rect_C(0, 0, 1.0f, 0.4f)).hide();
  196. overwrite_window+=overwrite_text.create(Vec2 (overwrite_window.clientWidth()*0.50f, -0.1f), MLTC(u"Are you sure you wish to overwrite selected item?", PL,u"Czy jesteś pewien że chcesz nadpisać\nwybrany element?"));
  197. overwrite_window+=overwrite_yes .create(Rect_C(overwrite_window.clientWidth()*0.25f, -0.25f, 0.28f, 0.07f), MLTC(u"Yes", PL,u"Tak")).func(OverwriteDo , T);
  198. overwrite_window+=overwrite_no .create(Rect_C(overwrite_window.clientWidth()*0.75f, -0.25f, 0.28f, 0.07f), MLTC(u"No" , PL,u"Nie")).func(OverwriteCancel, T);
  199. up .size(Vec2(0.16f, 0.06f));
  200. rename .size(Vec2(0.28f, 0.06f));
  201. remove .size(Vec2(0.24f, 0.06f));
  202. explore.size(Vec2(0.26f, 0.06f));
  203. quick .size(Vec2(0.06f, 0.06f));
  204. rect(Rect_C(0, 0, Min(1.3f, D.w2()), Min(1.28f, D.h2())));
  205. T.ext (ext);
  206. T.path(path, sub_path );
  207. T.io (load, save, user);
  208. return T;
  209. }
  210. WindowIO& WindowIO::ext(C Str &ext, C Str &desc)
  211. {
  212. Memt<Str> exts; Split(exts, ext, '|'); REPA(exts)if(!exts[i].is())exts.remove(i, true); // remove empty extensions and keep order
  213. if(_dir_operate && !exts.elms())return T; // mode operating on directories requires at least one extension, so if none are specified and we're in that mode, then don't apply the changes
  214. T._ext=ext; T._ext_desc=desc; _dot_exts.setNum(exts.elms()); FREPAO(_dot_exts)=S+'.'+exts[i];
  215. return T;
  216. }
  217. WindowIO& WindowIO::path(C Str &path, C Str &sub_path)
  218. {
  219. T. _path=Replace(NormalizePath(MakeFullPath(path)), '/', '\\').tailSlash(true);
  220. T._sub_path=Replace(NormalizePath( sub_path ), '/', '\\').tailSlash(true); if(StartsPath(_sub_path, ".."))_sub_path.clear();
  221. #if IOS // on iOS we can only write to "SystemPath(SP_APP_DATA)", so make sure that 'T._path' always starts with that path
  222. Str full=T._path+T._sub_path, root=SystemPath(SP_APP_DATA);
  223. if(StartsPath(T._path, root)) // T._path already starts with root - "/../documents/xxx" starts with "/../documents"
  224. {
  225. // do nothing as paths are already correct
  226. }else
  227. if(StartsPath(full, root)) // T._path starts with root but only after combining with T._sub_path - "/../"+"documents/xxx" starts with "/../documents"
  228. {
  229. T._path = root .tailSlash(true);
  230. T._sub_path=SkipStartPath(full, T._path).tailSlash(true);
  231. }else // path does not start with root at all
  232. {
  233. T._path=root.tailSlash(true);
  234. T._sub_path.clear();
  235. }
  236. #endif
  237. if(visible())getList();
  238. return T;
  239. }
  240. WindowIO& WindowIO::name(C Str &name)
  241. {
  242. textline.set(name);
  243. return T;
  244. }
  245. WindowIO& WindowIO::level(Int level)
  246. {
  247. super::level(level );
  248. rename_window.level(level+1);
  249. remove_window.level(level+1);
  250. overwrite_window.level(level+1);
  251. return T;
  252. }
  253. WindowIO& WindowIO::io(void (*load)(C Str &name, Ptr user), void (*save)(C Str &name, Ptr user), Ptr user)
  254. {
  255. T._load =load;
  256. T._save =save;
  257. T._func_user=user;
  258. return T;
  259. }
  260. WindowIO& WindowIO::modeDirSelect()
  261. {
  262. if(_mode!=WIN_IO_DIR)
  263. {
  264. _mode=WIN_IO_DIR;
  265. list._columns_hidden=true;
  266. if(list.columns()>=2)
  267. {
  268. list.column(0).width+=list.column(1).width;
  269. list.column(1).hide();
  270. }
  271. list.cur_mode=LCM_MOUSE;
  272. rename.hide();
  273. remove.hide();
  274. setRect(); // reset rect because of hidden buttons
  275. }
  276. return T;
  277. }
  278. WindowIO& WindowIO::modeDirOperate()
  279. {
  280. if(!_dir_operate && _dot_exts.elms()) // enable only if there is at least one extension specified
  281. {
  282. _dir_operate=true;
  283. }
  284. return T;
  285. }
  286. Str WindowIO::final( )C {return final(textline());}
  287. Str WindowIO::final(C Str &name)C // this will always include 'path', or empty string on error
  288. {
  289. Str final=NormalizePath(FullPath(name) ? name : path()+subPath()+name);
  290. return (!path().is() || StartsPath(final, path())) ? final : S;
  291. }
  292. Bool WindowIO::goodExt(C Str &name)C
  293. {
  294. if(!_dot_exts.elms())return true; // no extensions specified - support all of them
  295. FREPA(_dot_exts)if(Ends(name, _dot_exts[i]))return true;
  296. return false;
  297. }
  298. void WindowIO::Ok()
  299. {
  300. Edit::FileParams fp=final(); if(fp.name.is())
  301. {
  302. if(_mode==WIN_IO_DIR)
  303. {
  304. if(_load)_load(fp.name, _func_user);
  305. hide(); // hide at the end, in case it will delete this object
  306. // !! don't perform any operations on this object afterwards !!
  307. }else
  308. {
  309. // try entering the path if possible
  310. {
  311. FileInfo f;
  312. if(f.getSystem(fp.name))
  313. if(f.type==FSTD_DRIVE || f.type==FSTD_DIR)
  314. if(_dir_operate ? (f.type!=FSTD_DIR || !goodExt(fp.name)) : true)
  315. {
  316. path(_path, SkipStartPath(fp.name, _path));
  317. getList();
  318. list.scrollTo(0, true);
  319. textline.clear();
  320. return;
  321. }
  322. }
  323. // perform operation on file
  324. {
  325. Bool hide=true;
  326. if(ext_mode
  327. && ((_mode==WIN_IO_SAVE) ? _dot_exts.elms()>=1 : _dot_exts.elms()==1) // for saving add if we have at least 1, for other mode add if we have only 1
  328. && !goodExt(fp.name)
  329. && (ext_mode==WIN_IO_EXT_ALWAYS || !GetExt(fp.name).is()))
  330. fp.name+=_dot_exts[0];
  331. if(_mode==WIN_IO_LOAD){WindowIORecent(GetPath(fp.name)); if(_load)_load(fp.encode(), _func_user);}
  332. else {hide=!overwriteAsk(fp.name);}
  333. if(hide)T.hide(); // hide at the end, in case it will delete this object
  334. // !! don't perform any operations on this object afterwards !!
  335. }
  336. }
  337. }
  338. }
  339. void WindowIO::createDir()
  340. {
  341. if(!textline().is())Gui.msgBox("Information", "Please first enter the folder name in the textline.");else
  342. {
  343. Edit::FileParams fp=final(); if(fp.name.is() && FCreateDirs(fp.name))
  344. {
  345. path(_path, SkipStartPath(fp.name, _path));
  346. getList();
  347. textline.clear();
  348. }
  349. }
  350. }
  351. void WindowIO::renameDo()
  352. {
  353. if(File *f=list())if(f->type!=FSTD_DRIVE)
  354. {
  355. _op_name=path()+subPath()+f->name;
  356. rename_window .setTitle(S+MLTC(u"Rename \"", PL,u"Zmień nazwę \"")+f->name+'"').activate();
  357. rename_textline.set (f->name).selectExtNot();
  358. }
  359. }
  360. void WindowIO::removeAsk()
  361. {
  362. if(File *f=list())if(f->type!=FSTD_DRIVE)
  363. {
  364. _op_name=path()+subPath()+f->name;
  365. remove_window.setTitle(MLT(S+"Move to Recycle Bin \""+f->name+'"',
  366. PL,S+u"Przenieś do kosza \"" +f->name+'"')).activate();
  367. remove_yes.activate();
  368. }
  369. }
  370. void WindowIO::removeDo()
  371. {
  372. if(FRecycle(_op_name))
  373. {
  374. textline.clear();
  375. getList();
  376. }
  377. remove_window.hide(); disabled(false); list.activate();
  378. }
  379. void WindowIO::removeCancel()
  380. {
  381. remove_window.hide(); disabled(false); list.activate();
  382. }
  383. Bool WindowIO::overwriteAsk(C Str &name)
  384. {
  385. if(_save)
  386. {
  387. _op_name=name;
  388. FCreateDirs(GetPath(name));
  389. if(!FExistSystem(name))
  390. {
  391. overwriteDo();
  392. return true; // don't close the window because we've already closed it inside 'overwriteDo'
  393. }else
  394. {
  395. overwrite_window.setTitle(MLT(S+"Overwrite \""+GetBase(name)+'"',
  396. PL,S+u"Nadpisz \"" +GetBase(name)+'"')).activate();
  397. overwrite_yes.activate();
  398. return true; // don't close the window because we're waiting for overwrite decision
  399. }
  400. }
  401. return false; // close the window
  402. }
  403. void WindowIO::overwriteDo()
  404. {
  405. WindowIORecent(GetPath(_op_name));
  406. if(_save)_save(_op_name, _func_user);
  407. overwrite_window.hide(); disabled(false);
  408. hide(); // hide at the end, in case it will delete this object !! don't perform any operations on this object afterwards !!
  409. }
  410. void WindowIO::overwriteCancel()
  411. {
  412. overwrite_window.hide(); disabled(false); list.activate();
  413. }
  414. void WindowIO::exploreDo()
  415. {
  416. if(_path.is() || _sub_path.is())Explore(_path+_sub_path);
  417. }
  418. WindowIO& WindowIO::fullScreen()
  419. {
  420. FlagDisable(flag, WIN_MOVABLE|WIN_RESIZABLE);
  421. _border=0.03f;
  422. rect(D.rect());
  423. return T;
  424. }
  425. /******************************************************************************/
  426. void WindowIO::setBar()
  427. {
  428. Str ext=_ext_desc; if(!ext.is())FREPA(_dot_exts){if(ext.is())ext+=", "; ext+=SkipStart(_dot_exts[i], ".");}
  429. #if IOS // on iOS we can only write to "SystemPath(SP_APP_DATA)", so always skip that part
  430. WIN_IO_PATH_MODE path_mode=((T.path_mode==WIN_IO_PM_FULL) ? WIN_IO_PM_PART : T.path_mode);
  431. #endif
  432. switch(path_mode)
  433. {
  434. case WIN_IO_PM_NONE:
  435. switch(_mode)
  436. {
  437. case WIN_IO_LOAD: setTitle(S+MLTC(u"Load ", PL,u"Wczytaj ")+ext); break;
  438. case WIN_IO_SAVE: setTitle(S+MLTC(u"Save ", PL,u"Zapisz " )+ext); break;
  439. case WIN_IO_DIR : setTitle( MLTC(u"Select Directory", PL,u"Wybierz Katalog")); break;
  440. }
  441. break;
  442. case WIN_IO_PM_PART:
  443. switch(_mode)
  444. {
  445. case WIN_IO_LOAD: setTitle(S+MLTC(u"Load ", PL,u"Wczytaj ")+ext+" - "+subPath()); break;
  446. case WIN_IO_SAVE: setTitle(S+MLTC(u"Save ", PL,u"Zapisz " )+ext+" - "+subPath()); break;
  447. case WIN_IO_DIR : if(FullPath(textline()))setTitle(textline());else setTitle(subPath()+textline()); break;
  448. }
  449. break;
  450. case WIN_IO_PM_FULL:
  451. switch(_mode)
  452. {
  453. case WIN_IO_LOAD: setTitle(S+MLTC(u"Load ", PL,u"Wczytaj ")+ext+" - "+SkipStartPath(path()+subPath(), DataPath())); break;
  454. case WIN_IO_SAVE: setTitle(S+MLTC(u"Save ", PL,u"Zapisz " )+ext+" - "+SkipStartPath(path()+subPath(), DataPath())); break;
  455. case WIN_IO_DIR : if(FullPath(textline()))setTitle(SkipStartPath(textline(), DataPath()));else setTitle(SkipStartPath(path()+subPath()+textline(), DataPath())); break;
  456. }
  457. break;
  458. }
  459. }
  460. /******************************************************************************/
  461. void WindowIO::getList()
  462. {
  463. file.clear();
  464. FileFind ff;
  465. if(_path.is() || _sub_path.is())ff.find (_path+_sub_path);
  466. else ff.findDrives( );
  467. for(; ff(); )if(!(ff.attrib&FATTRIB_HIDDEN))switch(ff.type)
  468. {
  469. case FSTD_DRIVE: if(ff.driveType()==DRIVE_DISK )file.New().set( ff.type, 0, ff.name.tailSlash(false)); break;
  470. case FSTD_DIR : file.New().set((_dir_operate && goodExt(ff.name)) ? FSTD_LINK : ff.type, 0, ff.name ); break;
  471. case FSTD_FILE : if(!_dir_operate && _mode!=WIN_IO_DIR && goodExt(ff.name))file.New().set( ff.type, ff.size, ff.name ); break;
  472. }
  473. list.setData(file).lit=-1;
  474. setBar();
  475. }
  476. /******************************************************************************/
  477. void WindowIO::setFile(C Str &name)
  478. {
  479. REPA(file)if(Equal(file[i].name, name))
  480. {
  481. list.cur=list.absToVis(i);
  482. if(list.cur>=0)list.scrollTo(list.cur, true, 1);
  483. return;
  484. }
  485. }
  486. /******************************************************************************/
  487. void WindowIO::back()
  488. {
  489. if(_sub_path.last()=='\\' || _sub_path.last()=='/')
  490. {
  491. _sub_path.removeLast();
  492. Str base=_GetBase(_sub_path);
  493. for(; _sub_path.is() && _sub_path.last()!='\\' && _sub_path.last()!='/'; )_sub_path.removeLast();
  494. getList();
  495. setFile(base);
  496. }
  497. }
  498. void WindowIO::enter(C Str &dir)
  499. {
  500. _sub_path+=dir;
  501. _sub_path.tailSlash(true);
  502. getList();
  503. list.scrollTo(0, true);
  504. }
  505. /******************************************************************************/
  506. WindowIO& WindowIO::hide()
  507. {
  508. if(visible())
  509. {
  510. super::hide();
  511. rename_window.hide();
  512. remove_window.hide();
  513. overwrite_window.hide();
  514. }
  515. return T;
  516. }
  517. WindowIO& WindowIO::show()
  518. {
  519. if(hidden())
  520. {
  521. super::show();
  522. if(_dot_exts.elms()==1)textline.set(SkipEnd(textline(), _dot_exts[0])); // skip only if we have 1 extension specified
  523. getList();
  524. }
  525. return T;
  526. }
  527. WindowIO& WindowIO::activate()
  528. {
  529. super::activate();
  530. return T;
  531. }
  532. WindowIO& WindowIO::save()
  533. {
  534. _mode=WIN_IO_SAVE;
  535. setBar();
  536. return activate();
  537. }
  538. WindowIO& WindowIO::load()
  539. {
  540. overwrite_window.hide();
  541. _mode=WIN_IO_LOAD;
  542. setBar();
  543. return activate();
  544. }
  545. /******************************************************************************/
  546. Rect WindowIO::sizeLimit()C
  547. {
  548. Rect r=super::sizeLimit();
  549. r.min.set(Max(0.70f, ((up .visible() && up .is()) ? up .rect().w() : 0)
  550. + ((rename .visible() && rename .is()) ? rename .rect().w() : 0)
  551. + ((remove .visible() && remove .is()) ? remove .rect().w() : 0)
  552. + ((explore.visible() && explore.is()) ? explore.rect().w() : 0)
  553. + ((quick .visible() && quick .is()) ? quick .rect().w() : 0)
  554. + 0.03f) + _border*2, 0.48f+_border*2);
  555. return r;
  556. }
  557. /******************************************************************************/
  558. void WindowIO::setRect()
  559. {
  560. Rect r(0, -clientHeight(), clientWidth(), 0); r.extendX(-_border).min.y+=_border; r.max.y-=_border*0.5f; // extend top less because there's always the window bar
  561. // top
  562. Flt w=r.w(), bw=0; Int n=0;
  563. if(up .is() && up .visible()){bw+=up .rect().w(); n++;}
  564. if(rename .is() && rename .visible()){bw+=rename .rect().w(); n++;}
  565. if(remove .is() && remove .visible()){bw+=remove .rect().w(); n++;}
  566. if(explore.is() && explore.visible()){bw+=explore.rect().w(); n++;}
  567. if(quick .is() && quick .visible()){bw+=quick .rect().w(); n++;}
  568. n--; Flt s=((n>0) ? (w-bw)/n : 0); Vec2 pos=r.lu();
  569. up .pos(pos); if(up .is() && up .visible())pos.x+=up .rect().w()+s;
  570. rename .pos(pos); if(rename .is() && rename .visible())pos.x+=rename .rect().w()+s;
  571. remove .pos(pos); if(remove .is() && remove .visible())pos.x+=remove .rect().w()+s;
  572. explore.pos(pos); if(explore.is() && explore.visible())pos.x+=explore.rect().w()+s;
  573. quick .pos(pos); if(quick .is() && quick .visible())pos.x+=quick .rect().w()+s;
  574. // bottom
  575. create_dir.rect(Rect_LD(r.ld(), 0.38f, 0.06f));
  576. cancel .rect(Rect_RD(r.rd(), 0.30f, 0.07f));
  577. ok .rect(Rect_RD(cancel.rect().ru()+Vec2(0, 0.02f), 0.30f, 0.07f));
  578. textline .rect(Rect(r.min.x, ok.rect().min.y, ok.rect().min.x-_border, ok.rect().max.y));
  579. // middle
  580. region.rect(Rect(r.min.x, textline.rect().max.y+0.04f, r.max.x, rename.rect().min.y-0.03f));
  581. list.columnWidth(0, region.rect().w()-region.slidebarSize()-list.columnWidth(1));
  582. }
  583. WindowIO& WindowIO::rect(C Rect &rect)
  584. {
  585. if(T.rect()!=rect)
  586. {
  587. super::rect(rect);
  588. setRect();
  589. }
  590. return T;
  591. }
  592. /******************************************************************************/
  593. void WindowIO::update(C GuiPC &gpc)
  594. {
  595. Int list_cur=list.cur;
  596. super::update(gpc);
  597. if(Gui.window()==&rename_window) // rename
  598. {
  599. if((Kb.k(KB_ENTER) || Kb.k(KB_NPENTER)) && Kb.k.first() && rename_textline().is())
  600. {
  601. Kb.eatKey();
  602. if(FRename(_op_name, final(rename_textline())))
  603. {
  604. getList();
  605. setFile(rename_textline());
  606. }
  607. rename_window.hide(); disabled(false); list.activate();
  608. }else
  609. if((Kb.k(KB_ESC) || Kb.k(KB_NAV_BACK)) && Kb.k.first() || Ms.bp(2)){Kb.eatKey(); Ms.eat(2); rename_window.hide(); disabled(false); list.activate();}
  610. }else
  611. if(Gui.window()==&remove_window) // delete
  612. {
  613. if((Kb.k(KB_ESC) || Kb.k(KB_NAV_BACK)) && Kb.k.first() || Ms.bp(2)){Kb.eatKey(); Ms.eat(2); removeCancel();}
  614. }else
  615. if(Gui.window()==&overwrite_window) // overwrite
  616. {
  617. if((Kb.k(KB_ESC) || Kb.k(KB_NAV_BACK)) && Kb.k.first() || Ms.bp(2)){Kb.eatKey(); Ms.eat(2); overwriteCancel();}
  618. }
  619. disabled(rename_window.visible() || remove_window.visible() || overwrite_window.visible());
  620. if(Gui.window()==this && enabled())
  621. {
  622. if((Gui.kb()==&list && Kb.k(KB_BACK)) || (Gui.ms()==&list && (Ms.bp(4) || Ms.bp(1))))
  623. {
  624. Kb.eatKey();
  625. Ms.eat(1);
  626. Ms.eat(4);
  627. if(_mode==WIN_IO_DIR)textline.clear();
  628. back();
  629. }else
  630. if(Kb.kf(KB_F2 ) ){Kb.eatKey(); renameDo ();}else // rename
  631. if(Kb.kf(KB_DEL) && Gui.kb()!=&textline){Kb.eatKey(); removeAsk();}else // remove
  632. if(Kb.kf(KB_F4 ) ){Kb.eatKey(); exploreDo();} // explore
  633. // enter/save/load
  634. if(_mode==WIN_IO_DIR)
  635. {
  636. if(Gui.ms()==&list && Ms.bp(0) && !Ms.bd(0) && list.cur>=0)
  637. {
  638. if(File *f=list())
  639. {
  640. textline.clear();
  641. enter(f->name);
  642. }
  643. }else
  644. if(Gui.kb()==&list && (Kb.k(KB_ENTER) || Kb.k(KB_NPENTER)) && Kb.k.first() && (list.cur>=0 || list.lit>=0))
  645. {
  646. if(File *f=list((list.cur>=0) ? list.cur : list.lit))
  647. {
  648. Kb.eatKey();
  649. textline.clear();
  650. enter(f->name);
  651. }
  652. }else
  653. if(list.cur>=0)REPA(Touches)if(Touches[i].guiObj()==&list && Touches[i].tapped())
  654. {
  655. if(File *f=list())
  656. {
  657. textline.clear();
  658. enter(f->name);
  659. }
  660. break;
  661. }
  662. if((Kb.k(KB_ENTER) || Kb.k(KB_NPENTER)) && Kb.k.first()){Kb.eatKey(); Ok();} // !! don't perform any operations on this object after 'Ok' !!
  663. }else
  664. {
  665. // change content of TextLine element depending on selected list element
  666. if(list_cur!=list.cur)
  667. if(File *f=list())
  668. if(f->type==(_dir_operate ? FSTD_LINK : FSTD_FILE))textline.set(f->name);
  669. Bool touch_db=false;
  670. // enter directory because of the list (enter or double-click)
  671. if(list.cur>=0)
  672. {
  673. REPA(Touches)if(Touches[i].guiObj()==&list && Touches[i].db()){touch_db=true; break;}
  674. if((Gui.kb()==&list && (Kb.k (KB_ENTER) || Kb.k(KB_NPENTER)) && Kb.k.first())
  675. || (Gui.ms()==&list && Ms.bd(0 ) )
  676. || touch_db)
  677. if(File *f=list())
  678. if(f->type==FSTD_DRIVE || f->type==FSTD_DIR)
  679. {
  680. Kb.eatKey();
  681. Ms.eat(0);
  682. enter(f->name);
  683. return;
  684. }
  685. }
  686. if((Kb.k(KB_ENTER) || Kb.k(KB_NPENTER)) && Kb.k.first() || (Gui.ms()==&list && Ms.bd(0) && list.cur>=0) || touch_db)
  687. {
  688. Kb.eatKey();
  689. //Ms.eat(0); don't eat the button on purpose, so Gui.ms() won't be immediately changed
  690. Ok();
  691. // !! don't perform any operations on this object after 'Ok' !!
  692. }
  693. }
  694. }
  695. }
  696. /******************************************************************************/
  697. }
  698. /******************************************************************************/