function returnpath = filedlg(pathstr, mask, type, default, promptstr);
% returnpath = fileDlg(pathstr, mask, type)
%
% pathstr = pathstr {.}
% mask = file mask {*}
% type = 'dirs' | 'files' | {'both'}
% promptstr = prompt

if nargin < 1; pathstr = cd; end;
if strcmp(pathstr(length(pathstr)), filesep)
   pathstr = pathstr(1:length(pathstr)-1);
end;

if nargin < 2; mask = '*'; end;
if nargin < 3; type = ''; end;

switch type
case 'dirs'
   flbType = 'dirs';
case 'files'
   flbType = 'files';
otherwise
   type = 'both';
   flbType = 'nodirmask';
end

if nargin < 4;
   default = '';
end;

if nargin < 5;
   switch type
   case 'dirs'
      promptstr = 'Select a directory';
   otherwise
      promptstr = 'Select a file';
   end;
end;

gridSize = 9;
boxWidth =  [41 0];
boxHeight = [0 21];
editWidth = boxWidth;
editHeight = [0 2];
if strcmp(type, 'dirs')
   btnWidth =  floor((boxWidth-[2 0])/3);
else
   btnWidth =  floor((boxWidth-[1 0])/2);
end 

btnHeight = [0  4];
hSpacing =  [1  0];
vSpacing =  [0  1];

windowWidth =  hSpacing*2 + boxWidth;
windowHeight = vSpacing*4 + boxHeight + btnHeight + editHeight;
windowDims =  windowWidth + windowHeight;
set(0,'units','pixels');
screenSize = get(0,'screenSize');

position = [floor(screenSize(3:4)/2-windowDims*gridSize/2),windowDims*gridSize];
hDlg = dialog('Position',position,'Name',promptstr,'Visible','off','KeyPressFcn','dlgKeyPressFcn');

btnOpenPosition = [(windowWidth-2*(hSpacing+btnWidth))+vSpacing, (btnWidth+btnHeight)];
btnOpenPosition = btnOpenPosition*gridSize;
if strcmp(type, 'dirs')
   btnOpenString = 'Choose current dir.';
else
   btnOpenString = 'Open';
end

hBtnOpen = uicontrol( hDlg, ...
   'Style', 'pushbutton', ...
   'Callback', 'btnOpenCallback', ...
   'Units', 'pixels', ...
   'Position', btnOpenPosition, ...
   'String', btnOpenString, ...
   'Tag', 'btnOpen'...
   );

btnCancelPosition = [(windowWidth-(hSpacing+btnWidth))+vSpacing, (btnWidth+btnHeight)];
btnCancelPosition = btnCancelPosition * gridSize;
hBtnCancel = uicontrol( hDlg, ...
   'Style', 'pushbutton', ...
   'Callback', 'btnCancelCallback', ...
   'Units', 'pixels', ...
   'Position', btnCancelPosition, ...
   'String', 'Cancel', ...
   'Tag', 'btnCancel'...
   );

if strcmp(type,'dirs')
   btnChDirPosition = [hSpacing+vSpacing, btnWidth + btnHeight]*gridSize;
   hBtnChDir = uicontrol( hDlg, ...
      'Style', 'pushbutton', ...
      'Callback', 'btnChDirCallback', ...
      'Units', 'pixels', ...
      'Position', btnChDirPosition, ...
      'String', 'Change dir', ...
      'Tag', 'btnChDir'...
      );
end

lstFilePosition = [(hSpacing + 2*vSpacing + btnHeight), (boxWidth + boxHeight)]*gridSize;
% change mask once flb code is modified.
hLstFile = fileListBox(hDlg, pathstr, mask, flbType, ...
   'Units', 'pixels', ...
   'Position', lstFilePosition, ...
   'Callback', 'lstFileCallback', ...
   'FontName', 'FixedWidth', ...
   'Tag', 'lstFile', ...
   'BackgroundColor', 'w' ...
   );

editPathPosition = [vSpacing * 3 + boxHeight + btnHeight + hSpacing, editHeight+editWidth]*gridSize;
hEditPath = uicontrol(hDlg, ...
   'Style', 'edit', ...
   'Callback', 'editPathCallback', ...
   'Units', 'pixels', ...
   'Position', editPathPosition, ...
   'HorizontalAlignment', 'left', ...
   'String', pathstr, ...
   'FontName', 'FixedWidth', ...
   'BackgroundColor', 'w', ...
   'UserData', pathstr, ...
   'Tag', 'editPath'...
   );
   


set(hDlg, 'UserData', struct('pathstr',pathstr,'mask',mask,'type',type,'flbType',flbType,'curfile',[]));
set(hDlg, 'Visible', 'on');
waitfor(hDlg,'Visible','off');

if ishandle(hDlg)
   pathstr = getfield(get(hDlg,'UserData'),'pathstr');
   if not(isempty(getfield(get(hDlg, 'UserData'), 'curfile')))
      if strcmp(type, 'dirs'); fs = ''; else fs = filesep; end;
      returnpath = [pathstr fs getfield(getfield(get(hDlg, 'UserData'), 'curfile'), 'name')];
   else
      returnpath = default;
   end;
   close(hDlg)
else 
   returnpath = default;
end


return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function btnOpenCallback
type = getfield(get(gcbf,'UserData'),'type');
if not(strcmp(type, 'dirs'))
   hFLB = findobj(get(gcbf, 'Children'), 'Tag', 'lstFile');
   
   if ishandle(hFLB)
      i = get(hFLB, 'Value');
      fileList = get(hFLB, 'UserData');
      curfile = fileList(i);
      
      if curfile.isdir
         changeDirectory(gcbf);      
      else
         set(gcbf, 'UserData', setfield(get(gcbf, 'UserData'), 'curfile', curfile));
         set(gcbf, 'Visible', 'off');
      end
   else
      set(gcbf, 'UserData', setfield(get(gcbf, 'UserData'), 'curfile', []));
      set(gcbf, 'Visible', 'off');
   end;
else
   pathstr = getfield(get(gcbf,'UserData'),'pathstr');
   temp = struct('name','','bytes',0);
	set(gcbf, 'UserData', setfield(get(gcbf, 'UserData'), 'curfile', temp));
   set(gcbf, 'Visible', 'off');
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function btnCancelCallback
set(gcbf, 'UserData', setfield(get(gcbf, 'UserData'), 'curfile', []));
set(gcbf, 'Visible', 'off');
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function lstFileCallback
if strcmp(get(gcbf, 'SelectionType'),'open')
   type = getfield(get(gcbf,'UserData'),'type');
   if strcmp(type,'dirs')
      % default is chdir
      btnChDirCallback;
   else
      btnOpenCallback;
   end
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function btnChDirCallback

hFLB = findobj(get(gcbf, 'Children'), 'Tag', 'lstFile');
if ishandle(hFLB)
   i = get(hFLB, 'Value');
   fileList = get(hFLB, 'UserData');
   curfile = fileList(i);
   
   if curfile.isdir
      changeDirectory(gcbf);      
   end
end;

return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function changeDirectory(hDialog)
hFLB = findobj(get(hDialog, 'Children'), 'Tag', 'lstFile');

if ishandle(hFLB)
   i = get(hFLB, 'Value');
   fileList = get(hFLB, 'UserData');
   curfile = fileList(i);
   set(hDialog, 'UserData', setfield(get(hDialog, 'UserData'), 'curfile', curfile));
   
   if curfile.isdir
      name = curfile.name;
      mask = getfield(get(hDialog,'UserData'),'mask');
      pathstr = getfield(get(hDialog,'UserData'),'pathstr');
      flbType = getfield(get(hDialog,'UserData'),'flbType');
      if not(strcmp(name,'..'))
         newpathstr = [pathstr filesep name];
      else
         newpathstr = pathstr;
         newpathstr = newpathstr(1:max(findstr(newpathstr, filesep))-1);
      end
      set(hDialog,'UserData', setfield(get(hDialog, 'UserData'), 'pathstr', newpathstr));
      fileListBox(hFLB, newpathstr, mask, flbType);
      hEdit = findobj(get(hDialog, 'Children'), 'Tag', 'editPath');
      if ishandle(hEdit)
         set(hEdit, 'String', newpathstr);
      end
   end
end;
return;

function dlgKeyPressFcn
KEY_ENTER = 13;
KEY_ESC   = 27;
switch get(gcbf, 'CurrentChar');
case KEY_ENTER
   btnOpenCallback
case KEY_ESC
   btnCancelCallback
end;
return;

function editPathCallback
d = get(gcbo, 'String');
if strcmp(d(length(d)), filesep);
   d=d(1:length(d)-1);
end;
if exist([d filesep])==7
   hFLB = findobj(get(gcbf, 'Children'), 'Tag', 'lstFile');
   mask = getfield(get(gcbf,'UserData'),'mask');
   set(gcbf, 'UserData', setfield(get(gcbf,'UserData'),'pathstr',d));
   flbType = getfield(get(gcbf,'UserData'),'flbType');
   fileListBox(hFLB,d, mask, flbType);
   set(gcbo, 'UserData', d);
else
   set(gcbo,'String',get(gcbo,'UserData'));
end;
return