function gcd(RecursiveArg)
%
% gcd.m--Changes current directory using a graphical interface.
%
%  Syntax: gcd

% Developed in Matlab 5.3.1 on UNIX Solaris 5.8.
% Kevin Bartlett (bartlett@soest.hawaii.edu), 11/2000.
%------------------------------------------------------------------------------

% N.B. Code based on Matlab's listdlg.m function.

VERBOSE = 0; % Change to 0 if you don't like messages printed out after each gcd.

% Parse inputs. Gcd.m is called with no input arguments by the user; the program
% then calls itself recursively with one argument until the user exits.
if nargin == 0,
   RecursiveArg = 'setup';
elseif nargin ~= 1,
   error([mfilename '.m--Incorrect number of input arguments.'])
end % if

% Use the input argument to decide what is the appropriate action to perform.
switch RecursiveArg
   
case 'update' % Update window
   DirListBox = findobj('tag','DirListBox');
   [DirList,FileList] = DirContents(pwd);
   set(DirListBox,'value',1);
   set(DirListBox,'string',DirList);
   
   FileListBox = findobj('tag','FileListBox');
   set(FileListBox,'value',1);
   set(FileListBox,'string',FileList);
   
   DirTextBox = findobj('tag','DirTextBox');
   set(DirTextBox,'string',pwd);
   
case 'ok' % OK button callback

   % Get the name of the directory contained in editable text box.
   DirTextBox = findobj('tag','DirTextBox');
   DirString = get(DirTextBox,'string');
   
   if exist(DirString,'dir')~=7,
      % If requested directory does not exist, do nothing, continue with program...
   else
      % If requested directory does exist, change to the new directory, end program.
      cd(DirString);
      close;

      if VERBOSE == 1,
         disp(['Current directory changed to ' pwd]);
      end % if

   end  % if
   
case 'cancel' % Cancel button callback

   % Change back to original directory and end program.
   OrigDir = get(gcf,'userdata');
   cd(OrigDir);
   close;

   if VERBOSE == 1,
      disp(['Current directory (unchanged) is ' pwd]);
   end % if
   
case 'listclick' % DirListBox callback

   % If user clicks on a directory list item, change to the selected directory,
   % then update the window.
   DirListBox = findobj('tag','DirListBox');
   DirList = get(DirListBox,'string');
   ListIndex = get(DirListBox,'value');
   ChosenDir = DirList{ListIndex};
   cd(ChosenDir);   

   % Update the window.
   gcd('update');
   
case 'setup' % Set up window
   
   DirList = [];
   FileList = [];
   
   promptstring = {'Change to directory: '};
   InitialTextIndex = 1;
   
   OKString = 'OK';
   CancelString = 'cancel';
   fus = 8; % frame/uicontrol spacing, in pixels.
   ffs = 8; % frame/figure spacing, in pixels.
   ButtonHeight = 25; % pixels.
   
   % Define a "list area" for the two lists to fit into.
   ListAreaSize = [400 300];
   
   LineHeight = get(0,'defaultuicontrolfontsize')*1.5;  % height extent per line of uicontrol text, in pixels (approximate)
   
   FigPos = get(0,'defaultfigureposition');
   FigWidth = 2*(fus+ffs)+ListAreaSize(1);
   FigHeight = 2*ffs+6*fus+LineHeight*length(promptstring)+ListAreaSize(2)+ButtonHeight;
   FigPos = [FigPos(1) FigPos(2)+FigPos(4)-FigHeight FigWidth FigHeight];  % keep upper left corner fixed
   
   ButtonScale = 0.3; % Set to 1 to make the buttons use all available width.
   NumButtons = 2;
   AvailButtonWidth = (FigWidth-NumButtons*(ffs+fus)-fus);
   ButtonWidth = ButtonScale*AvailButtonWidth/NumButtons;
   ButtonCentres = [1:NumButtons].*AvailButtonWidth./(NumButtons+1);

   FigProps = { ...
         'resize'                 'off' ...
         'numbertitle'            'off' ...
         'windowstyle'            'modal' ...
         'createfcn'              ''    ...
         'position'               FigPos   ...
         'MenuBar'                'none' ...
         };
   
   figure(FigProps{:});
   
   % Keep the original directory as userdata. Cancelling the directory change causes the
   % current directory to revert back to this value.
   OrigDir = pwd;
   set(gcf,'userdata',OrigDir);
   
   % Make a frame around entire window contents.
   uicontrol('style','frame','position',[0 0 FigPos([3 4])])

   % Make a frame around the control buttons.
   uicontrol('style','frame','position',[ffs ffs 2*fus+ListAreaSize(1) 2*fus+ButtonHeight])   

   % Make a frame around the text boxes.
   uicontrol('style','frame', 'position',[ffs ffs+3*fus+ButtonHeight 2*fus+ListAreaSize(1) ...
         ListAreaSize(2)+3*fus+LineHeight*length(promptstring)])   
   
   prompt_text = uicontrol('style','text','string',promptstring,...
      'horizontalalignment','left','units','pixels',...
      'position',[ffs+fus FigPos(4)-(ffs+fus+LineHeight*length(promptstring)) ...
         ListAreaSize(1) LineHeight*length(promptstring)]);   
   
   ok_btn = uicontrol('style','pushbutton',...
      'string',OKString,...
      'position',[ffs+fus+ButtonCentres(1)-ButtonWidth ffs+fus ButtonWidth ButtonHeight],...
      'callback','gcd ok','FontWeight','bold','tag','OKButton');

   cancel_btn = uicontrol('style','pushbutton',...
      'string',CancelString,...
      'position',[ffs+2*fus+ButtonCentres(2) ffs+fus ButtonWidth ButtonHeight],...
      'callback','gcd(''cancel'')','FontWeight','bold');  
   
   % Define the locations of the two list boxes and the editable text box within the list area.
   ListBoxWidthPercent = 47;
   ListBoxWidth = ListAreaSize(1)*ListBoxWidthPercent/100;
   ListBoxHeightPercent = 92;
   ListBoxHeight = ListAreaSize(2)*ListBoxHeightPercent/100;
   TextBoxWidthPercent = 100;
   TextBoxWidth = ListAreaSize(1)*TextBoxWidthPercent/100;
   TextBoxHeightPercent = 100-ListBoxHeightPercent;
   TextBoxHeight = ListAreaSize(2)*TextBoxHeightPercent/100;
   
   DirListBox = uicontrol('style','listbox',...
      'position',[ffs+fus ffs+ButtonHeight+4*fus ListBoxWidth ListBoxHeight],...
      'string',DirList,...
      'backgroundcolor','w',...
      'tag','DirListBox',...
      'value',InitialTextIndex, ...
      'callback', 'gcd(''listclick'')');
   
   FileListBox = uicontrol('style','listbox',...
      'position',[ffs+fus+(ListAreaSize(1)-ListBoxWidth) ffs+ButtonHeight+4*fus ListBoxWidth ListBoxHeight],...
      'string',FileList,...
      'backgroundcolor',[1 1 1],...
      'tag','FileListBox',...
      'value',InitialTextIndex, ...
      'enable','off', ...
      'callback', '');
   
   DirTextBox = uicontrol('style','edit',...
      'position',[ffs+fus 2*ffs+ButtonHeight+ListBoxHeight+4*fus TextBoxWidth TextBoxHeight],...
      'string',OrigDir,...
      'backgroundcolor','w',...
      'tag','DirTextBox',...
      'value',InitialTextIndex, ...
      'HorizontalAlignment','left', ...
      'callback', ['gcd(''ok'')']);
      
   % Update the window.
   gcd('update');
   waitfor(gcf);
   
end % switch


%------------------------------------------------------------------------------
function [DirList,FileList] = DirContents(directory)
%
% DirContents.m--Makes a list of files in the specified directory and another
% list of sub-directories and returns them as cell arrays.
%
% Syntax: [DirList,FileList] = DirContents(directory)
%
% e.g.,   [DirList,FileList] = DirContents(pwd)

% Kevin Bartlett (bartlett@soest.hawaii.edu), 11/2000.
%------------------------------------------------------------------------------

DirStruct = dir;
DirCell = {DirStruct.name};
IsDir = {DirStruct.isdir};
FileList = {};
FileCount = 0;
DirList = {};
DirCount = 0;

for CellCount = 1:size(DirCell,2),
   
   if IsDir{CellCount}==1,
      DirCount = DirCount + 1;
      DirList{DirCount} = DirCell{CellCount};
   else
      FileCount = FileCount + 1;
      FileList{FileCount} = DirCell{CellCount};
   end % if
   
end % for

DirList = sort(DirList);
FileList = sort(FileList);

