function [P,units] = StructDlg(struct_def,title,dflt,fig_pos,visible,present_val)
% StructDlg - A structure based definition of an input GUI. Allows for a quick and
%             convenient text based definition of a GUI
%
%   StructDlg(struct_def, title, default_values, position)
%
% StructDlg creates a modal dialog box that contains a user interface (UI) control
% for each of the struct_def fields.
% In its simple form, StructDlg serves as a structure-based alternative to INPUTDLG
% and it is a convenient method for browsing and changing structure values
% (e.g. when the structure contains parameters).
% In its advanced form, StructDlg allows for a quick and convenient text based definition
% of a GUI that may contain many styles of UI controls such as edit, popup menus,
% radio buttons, toggles and more.
%
% When StructDlg is called the GUI is created and the user can set the
% values of the different UI controls (such as edit controls, radio
% buttons, popup menus, etc.)
% When the user is satisfied with his selections, he presses an OK button which closes the GUI.
% structdlg then returns a structure with the same field names as struct_def. The value of each
% field in the returned structure contains the value of the UI control of the same name.
% The title of the dialog box may be specified by adding a second string argument.
% The dflt_P argument is a structure that contains default values for the fields' values.
% These values will override  the default values specified in struct_def.
% Note that the dflt_P argument should contain the default values ONLY, not the entire
% definition as specified in struct_def. This is useful for allowing user-specific defaults that override the
% 'factory defaults'. A 4-element position vector can be specified by
% the forth argument. Position units are given in characters.
%
% The name of each field of struct_def is the default label of the corresponding input field
% (underscores are presented as spaces). In their simple form, struct_def fields may contain numeric values
% (limited to 2D matrixes) or single line strings.
%
% S.Duration      = 10;
% S.Time_Out      = 20;
% S.Weight_Matrix = [0.3 0.4; 3.4 9.1; 10 0.4];
% S.Comment       = 'No comment';
%
% For allowing more UI control styles and options the value of each struct_def field can be set to
% a cell array of up to four elements:
%     { value/definition   labels  limits  protected_flag }
% The first element determines the type (edit, radio button, pop-up menu and more) of the control and
% its default value.
% The second element allows to override the default label (the field name). Any occurrence of an asterisk
% ('*') in the label is replaced with the field name . This is useful when you want to add a text to the
% default label. For example, '* (kHz)' will add the unit KHz to the field name.
% This field is optional and merely changes the label of the UI control.
% The empty string can be used to indicate that the default label should be used.
% The third element can be used to specify limits to legal values that can be entered by the user.
% This is useful for numerical edit fields (see below.)
% The forth element is a logical element (0/1). Setting this element to 1 causes the UI control to be
% protected (disabled). The user can right-click on that control to unprotect (enable) it.
% This is useful when you want to indicate that the user should think before changing the current
% value of the control.
% Below are detailed examples of how to create all the styles and types of controls that structdlg supports.
%
% See also .\ref\StructDlg.html for more details
%
%     Numeric values: Limited to 2D matrixes of any size (including the empty matrix).
%                     The default value can be a numeric vector, or a string that is a valid Matlab
%                     expression, which its evaluation result is a numeric 2D matrix.
%                     In the later case, you must specify the limits ([] is equivalent to [-Inf Inf]),
%                     so 'StructDlg' will interpret the field as a numeric field.
%           Examples: S.center_frequency = { 2000 '* (Hz)' [30 50000] }; -> default of 2000, allowed range:[30 50000].
%                     S.my_parameter     = { [43 3 ; 56 12] } -> 2x2 matrix, no limits.
%                     S.size_of_matrix   = { [4 12] '' [1 Inf] }; -> default of [4 12], allowed range:[1 Inf].
%               Note: The values the user enters to the dialog box for numeric fields are being 'eval'-uated,
%                     so inputs such as (sin(0.34)+2)^my_func(34.2) or zeros(3,3) are possible.
%                     The field's numeric limits can be displayed by placing the mouse over the field.
%                     Numeric values may be also defined using the short notation:
%                     S.my_parameter     = 5;     default of 5, no limits.
%
%       Free Strings: Limited to one line string (no string arrays). If no default is required, use the
%                     empty string (''), otherwise the field will be treated as numeric.
%                     Strings can be also defined using the short notation:
%                     S.name             = '';
%
% List of Strings(1): One string that contain all the options, separated by '|'. The options will be
%                     presented as a radio buttons. The string that the user chooses will become the value
%                     of that field in P. A Default option can be specified by enclosing it with curly brackets.
%                     The chosen string is converted to numeric values if possible.
%            Example: S.colormap = {'hsv|{gray}|hot|bone|pink'};
%                   : S.Sampling_rate = {'11500|22000|{44000}' '* (Hz)'};
%
% List of Strings(2): One Cell-array of single strings. The options will be presented in a pop-up menu.
%                     The chosen option will be the value of that field in P. A default option can be
%                     specified by enclosing it with curly brackets. The chosen string is converted
%                     to numeric values if possible.
%           Examples: S.Sampling_frequency = { {'12207' '24414' '48828' '{97656}'} , '* (Hz)'};
%                     S.Filter_type = { {'bartlett' 'blackman' '{chebwin}' 'hamming'} };
%
%      Boolean (0/1): The value of the S field must be in the form: {'0' '1'}. A default value may be
%                     specified by the curly brackets.
%            Example: S.use_filter = { {'0','{1}'} };
%
%  File Name Dialogs: The value of the S field is a cell of one string that
%                     must start with 'uigetfile', 'uiputfile' or 'uigetdir'.
%                     The getfile/dir commands may be followed the arguments
%                     allowed by the Matlab command (see help UIGETFILE,
%                     UIPUTFILE and UIGETDIR for more details).
%                     a search filter enclosed by brackets. The user will be able to specify the file
%                     name directly by typing it,or to push a small pushbutton that will pop-up
%                     Matlab's uigetfile, uipufile or uigetdir.
%            Example: S.parameters_file = { {'uigetfile(''d:\my_dir\*.m'')'} };
%                     S.parameters_file = { ...
%                     {'uigetfile({''*.m'';''*.mat'';''*.*''},''File Selector'',''MultiSelect'', ''on'')'}};
%
%      Sub-Structure: S may contain substructures of the same format. The user will be able to push a
%                     push-button that will call 'StructDlg' recursively for the sub-structure.
%                     The current values of the sub-structure can be viewed by placing the mouse over
%                     the push-button.
%
%   Dependent Fields: (For numeric fields only) A numeric field may include a reference to the value of
%                     another numeric fields. This is done using a reserved word 'this' to refer to the
%                     structure.
%            Example: S.Window_size       = { 512 '' [10 1000] };
%                     S.Overlap           = {'this.Window_size / 2' '' [0 Inf]}; -> Note that
%                     a non-empty limits indicator is needed in order to indicate that this is a numeric field.
%
%              Notes: The value of the dependent field will be automatically updated when the values
%                     of the referenced fields changes. The automatically changed value will blink twice
%                     to alert the user. The user is then able to undo the automatic change using the
%                     mouse's right-click.
%                     It is not possible for a sub-structure field to reference fields in other sub-structures,
%                     or in other structure levels. It is possible for a field to reference fields in
%                     sub-structures of lower levels; however, this is highly not recommended.
%
%
%     'title' is the title of the dialog-box.'dflt' is a structure which contain default values for P.
%     These values will override  the default values specified in
%     struct_def.
%     Note that the dflt should contain the default values only, not the entire
%     definition as specified in S. This is useful for enabling user-specific defaults that override the
%     'factory defaults'.
%
%    See also: Struct2str, Browse_Struct
%
% Alon Fishbach, fishbach@northwestern.edu 12/15/04
%
% This code is provided "as is". Enjoy and feel free to modify it.
% Needless to say, the correctness of the code is not guarantied.

% AF 1/10/2005: Fixed a bug that crashed StructDlg when substructure were used.
% AF 1/10/2005: Allow for auto-updates even when the referenced field is not an edit UI

global rec_level

if ((isempty(rec_level)) | (rec_level <0))
   rec_level = 0;
end

if (exist('struct_def','var') ~= 1)
   rec_level = rec_level-1; % For delete function.
   return
end
if ((exist('title','var') ~= 1) | isempty(title))
   title = 'Input Form';
end
if (exist('dflt','var') ~= 1)
   dflt = struct([]);
end
if ((exist('visible','var') ~= 1) | isempty(visible))
   % 'Visible' is used mainly in recursive calls for the construction of a temporary hidden form for substructures.
   visible = 'on';
end
if (exist('present_val','var') ~= 1)
   present_val = []; % 'present_val' is used to pass the last value of sub-structure fields.
end

vert_spacing = 1;
font_size    = 11;
col          = 'k';
screen_size  = get_screen_size('char');
aspec_ratio  = screen_size(3)/screen_size(4);

if (isstruct(struct_def)) % Init
   rec_level = rec_level+1;
   if (isequal(visible,'on'))
      dflt = rm_ignore_dflt(dflt,struct_def);
      present_val = rm_ignore_dflt(present_val,struct_def);
   else
      dflt = rm_ignore_dflt(dflt,struct_def); % AF 6/20/02: Comment this line out if cuases problems.
      present_val = rm_ignore_dflt(present_val,struct_def);
   end
   [struct_def units limits protected] = split_def(struct_def);
   fnames = fieldnames(struct_def);
   fnames_lbl = build_labels(fieldnames(struct_def),units);
   max_width = (size(char(fnames_lbl),2) + 4) * font_size/7;
   tot_height = max(5,length(fnames_lbl)* (1+vert_spacing) + vert_spacing+2.5);
   recurssion_offset = 7*(rec_level-1);
   if ((exist('fig_pos','var') ~= 1) | isempty(fig_pos))
      fig_pos = [screen_size(3)/5+recurssion_offset  screen_size(4)-tot_height-4-recurssion_offset/aspec_ratio ...
         screen_size(3)*3/5  tot_height+2];
      specified_pos = 0;
   else
      if (tot_height+2 > fig_pos(4))
         height_addition = min(fig_pos(2)-0.5,(tot_height+2 -fig_pos(4)));
         fig_pos(2) = fig_pos(2) - height_addition;
         fig_pos(4) = fig_pos(4) + height_addition;
      end
      specified_pos = 1;
   end
   h_fig = figure( ...
      'NumberTitle',         'off',...
      'Name',                title, ...
      'Units',               'char', ...
      'position',            fig_pos, ...
      'keypress',            'StructDlg(get(gcbf,''CurrentCharacter''));', ...
      'color',               get(0,'DefaultuicontrolBackgroundColor'),...
      'Visible',             visible,...
      'DeleteFcn',           'StructDlg;', ...
      'CloseRequestFcn',     'StructDlg(''cancel'');',...
      'WindowStyle',         'modal'); % Change to noraml when debugging

   lbl = zeros(1,length(fnames_lbl));
   for i = 1:length(fnames_lbl)
      vert_pos = fig_pos(4)-i*(1+vert_spacing)-0.5;
      lbl(i)  = uicontrol(h_fig, ...
         'style',            'text', ...
         'units',            'char', ...
         'position',         [2.0 vert_pos max_width 1.5],...
         'String',           [fnames_lbl{i} ':'], ...
         'fontsize',         font_size, ...
         'Tag',              ['LBL_' fnames{i}], ...
         'ForegroundColor',  col, ...
         'horizon',          'right');
   end
   ud.error = [];
   ud.specified_pos = specified_pos;
   ud.col   = col;
   ud.width = 20;
   ud.units     = units;
   ud.dflt      = dflt;
   ud.limits    = limits;
   ud.protected = protected;
   ud = set_fields_ui(struct_def,h_fig,ud,[]);
   if (~isempty(present_val))
      ud.present_val = present_val;
      ud = set_fields_ui(struct_def,h_fig,ud,[]);
      ud = rmfield(ud,'present_val');
      set(h_fig,'UserData',ud);
   end

   OK_vert_pos = min(0.5,fig_pos(4)-tot_height);
   % OK_vert_pos = fig_pos(4)-tot_height;
   if (OK_vert_pos < 0)
      slider_step = fig_pos(4) / (abs(OK_vert_pos)+fig_pos(4));
      h_slider = uicontrol(h_fig, ...
         'style',         'slider', ...
         'callback',      'StructDlg(''slider_change'');', ...
         'Units',         'char', ...
         'position',      [0  0  3  fig_pos(4)/2], ...
         'SliderStep',    [slider_step/5 slider_step], ...
         'Max',           abs(OK_vert_pos), ...
         'value',         abs(OK_vert_pos), ...
         'Userdata',      abs(OK_vert_pos));
   end
   h_OK = uicontrol(h_fig, ...
      'style',         'pushbutton', ...
      'callback',      'StructDlg(''ok'');', ...
      'Units',         'char', ...
      'position',      [fig_pos(3)-40  OK_vert_pos  12  1.75], ...
      'String',        'ok', ...
      'FontName',      'Helvetica', ...
      'FontSize',      11, ...
      'FontWeight',    'normal');

   h_reset = uicontrol(h_fig, ...
      'style',         'pushbutton', ...
      'callback',      'StructDlg(''reset'');', ...
      'Units',         'char', ...
      'position',      [fig_pos(3)-27  OK_vert_pos  12  1.75], ...
      'String',        'reset', ...
      'FontName',      'Helvetica', ...
      'FontSize',      11, ...
      'FontWeight',    'normal');

   h_cancel = uicontrol(h_fig, ...
      'style',         'pushbutton', ...
      'callback',      'StructDlg(''cancel'');', ...
      'Units',         'char', ...
      'position',      [fig_pos(3)-14  OK_vert_pos  12  1.75], ...
      'String',        'cancel', ...
      'FontName',      'Helvetica', ...
      'FontSize',      11, ...
      'FontWeight',    'normal');

   if (rec_level >1) % For sub-forms (created with sub-structures) the cancel is disabled
      set(h_cancel,'Enable','off')
   end
   if (strcmp(visible,'on'))
      reorder_childs(h_fig)
      uiwait(h_fig);
   end
   ud    = get(h_fig,'UserData');
   P     = ud.vals;
   units = ud.units;
   delete(h_fig);

   % Following are callbacks from the form
elseif (iscell(struct_def) & ~isempty(struct_def))
   StructDlgCB(struct_def{1}); % Callback from one of the regular input fields. Processed in 'StructDlgCB'.

elseif (isstr(struct_def))
   % Other push buttons or context-menus in the form.
   [cmd args] = strtok(struct_def,'(');
   if (~isempty(args))
      args = {args(2:end-1)};
   end
   if (~isempty(cmd))
      switch (cmd)
         case 'unlock'
            unlockCB(args{1},gcbf);

         case 'undo'
            undoCB(args{1},gcbf);
            StructDlg(args);

         case {'reset', char(18)}
            ud    = get(gcbf,'UserData');
            set_fields_ui(ud.orig_def,gcbf,ud,[],args,1);

         case {'ok', char(15), char(10), char(13)}
            ud    = get(gcbf,'UserData');
            if (isempty(ud.error))
               uiresume(gcbf);
            else
               beep;
            end

         case {'cancel',char(27)}
            ud    = get(gcbf,'UserData');
            ud.vals = [];
            set(gcbf,'UserData',ud);
            uiresume(gcbf);

         case {'slider_change'}
            hgcbo = gcbo;
            val = get(hgcbo,'Userdata') - get(hgcbo,'Value');
            set(hgcbo,'UserData', get(hgcbo,'Value'));
            chld = get(gcbf,'Children');
            for i = 1:length(chld)
               if (chld(i) ~= hgcbo)
                  cur_pos = get(chld(i),'Position');
                  if (length(cur_pos) == 4) % i.e. not a uicontextmenu
                     set(chld(i),'Pos',cur_pos + [0 val 0 0]);
                     drawnow;
                  end
               end
            end

      end

   end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                        SUB FUNCTIONS                        %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Short Utility functions first:
%%
%%%%%%%%%%%%%
function [struct_def,units,limits,protected] = split_def(struct_def)
units     = struct([]);
limits    = struct([]);
protected = struct([]);
fnames = fieldnames(struct_def);
fvals  = struct2cell(struct_def);
for i = 1:length(fnames)
   switch (class(fvals{i}))
      case 'cell'
         if (length(fvals{i}) >=1)
            struct_def = setfield(struct_def,fnames{i}, fvals{i}{1});
         else
            struct_def = setfield(struct_def,fnames{i}, '');
         end
         if (length(fvals{i}) >=2)
            units = setfield(units,{1},fnames{i}, fvals{i}{2});
         end
         if (length(fvals{i}) >=3)
            if (~isempty(fvals{i}{3}))
               limits = setfield(limits,{1},fnames{i}, fvals{i}{3});
            end
         end
         %          if (length(fvals{i}) >=4)
         %             if (~isempty(fvals{i}{4}))
         %                labels = setfield(labels,{1},fnames{i}, fvals{i}{4});
         %             end
         %          end
         if (length(fvals{i}) >=4)
            if (~isempty(fvals{i}{4}) & fvals{i}{4} == 1)
               protected = setfield(protected,{1},fnames{i},1);
            end
         end

      case 'struct'

      otherwise
   end
end

%----------------------------------------------
function dflt = rm_ignore_dflt(dflt,struct_def)
fnames = fieldnames(struct_def);
fvals  = struct2cell(struct_def);
for i = 1:length(fnames)
   switch (class(fvals{i}))
      case 'cell'
         if (length(fvals{i}) >=5)
            if (~isempty(fvals{i}{5}) & fvals{i}{5} == 1 & isfield(dflt,fnames{i}))
               dflt = rmfield(dflt,fnames{i});
            end
         end

      case 'struct'
         % tmp = rm_ignore_dflt(getfield(dflt,fnames{i}),getfield(struct_def,fnames{i}));
         % dflt = setfield(dflt,fnames{i},tmp);

      otherwise
   end
end

%%%%%%%%%%%%%
function fnames_lbl = build_labels(fnames,units);
%
fnames_lbl = strrep(fnames,'_',' ');
f_units = fieldnames(units);
v_units = struct2cell(units);
for i = 1:length(f_units)
   if (ischar(v_units{i}) & ~isempty(v_units{i}))
      index = strmatch(f_units{i},fnames,'exact');
      if (~isempty(index))
         fnames_lbl{index} = strrep(v_units{i},'*',fnames_lbl{index});
         % fnames_lbl{index} = [fnames_lbl{index} ' (' v_units{i} ')'];
      end
   end
end
return;

%%%%%%%
% So the tab will always bring you to the first editable field (a bug-fix for Matlab Ver 6.1)
function reorder_childs(h_fig)
chld = get(h_fig,'Children');
if (length(chld) ==1)
   return;
end
for i = length(chld):-1:1
   if (strcmp(get(chld(i),'Type'),'uicontrol') & ~strcmp(get(chld(i),'Style'),'text') & ...
         strcmp(get(chld(i),'Enable'),'on'))
      ind = i;
      break;
   end
end
chld = [chld([1:ind-1 ind+1:end]) ; chld(ind)];
set(h_fig,'Children',chld);
return

%%%%%%%%
function tooltipstr = struct_tooltip(S,units)
try
   tooltipstr = char(struct2str(S,units,70));
catch
   tooltipstr = ['sub-structure info can not be displayed. ' lasterr];
end
tooltipstr = sprintf('%s', [tooltipstr repmat(char(10),size(tooltipstr,1),1)]');
return;

%%%%%%%%
function timer(t)
tic;
while(toc < t)
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%  CREATION AND RESET OF UI's  %%%%%%%%%%%%%%%%%%%%%%
function ud = set_fields_ui(def,h_fig,ud,present_val,fnames,ignore_defaults)
%
% vals = def;
if ((exist('fnames','var') ~= 1) | isempty(fnames))
   fnames = fieldnames(def);
end
if (exist('ignore_defaults') ~= 1)
   ignore_defaults = 0;
end
if (~isfield(ud,'vals'))
   ud.vals = [];
end
orig_def = def;
if (isfield(ud,'present_val'))
   dflt = ud.present_val;
else
   dflt = ud.dflt;
end
ud.orig_def = orig_def;
ud.def = def;
if (~isfield(ud,'auto_update')) % needed for self-reference fields
   ud.auto_update = cell2struct(cell(size(fieldnames(def))),fieldnames(def));
end
if (~isfield(ud,'undo_vals'))
   ud.undo_vals = cell2struct(cell(size(fieldnames(def))),fieldnames(def));
end
set(h_fig,'UserData',ud);

fig_pos = get(h_fig, 'Position');
fig_width = fig_pos(3);
for i = 1:length(fnames)
   h_lbl = findobj(h_fig,'Tag',['LBL_' fnames{i}]);
   lbl_pos = get(h_lbl,'Position');
   h = findobj(h_fig,'Tag',fnames{i});
   val = getfield(def,fnames{i});
   if (iscell(val) & isempty(val))
      val = '';
   end
   if (isfield(ud.limits,fnames{i}))
      limits = getfield(ud.limits,fnames{i});
      if (isempty(limits))
         limits = [-Inf Inf];
         ud.limits = setfield(ud.limits,{1},fnames{i},limits);
      end
   elseif (isnumeric(val))
      limits = [-Inf Inf];
      ud.limits = setfield(ud.limits,{1},fnames{i},limits);
   else
      limits = [];
   end
   if (isfield(dflt,fnames{i}) & ~ignore_defaults)
      dflt_val = getfield(dflt,fnames{i});
   else
      dflt_val = [];
   end

   % val is a numeric or should be evaluated to a numeric value
   if (~isempty(limits) & ~isstruct(limits))
      ud = reset_numeric_field(h_fig,h,fnames{i},val,lbl_pos,limits,ud,dflt_val,ignore_defaults);

   elseif (ischar(val))
      sep = findstr(val,'|');
      if (isempty(sep))
         if (~isempty(dflt_val))
            val = dflt_val;
         end
         ud = reset_char_field(h_fig,h,fnames{i},val,lbl_pos,ud);

      else
         ud = reset_radio_field(h_fig,h,fnames{i},val,lbl_pos,ud,sep,dflt_val);
      end

   elseif (iscell(val))
      % Special requests
      if ((length(val) == 1) & ischar(val{1}))
         if (~isempty(strmatch('uigetfile',val{1})) | ...
               ~isempty(strmatch('uiputfile',val{1})) | ...
               ~isempty(strmatch('uigetdir',val{1})) )
            ud = reset_getfile_field(h_fig,h,fnames{i},val,lbl_pos,ud,dflt_val);
         end
      elseif ((length(val) == 2) & strmatch(val{1},{'0','{0}'},'exact') & strmatch(val{2},{'1','{1}'},'exact'))
         ud = reset_checkbox_field(h_fig,h,fnames{i},val,h_lbl,lbl_pos,ud,dflt_val);
      else
         ud = reset_popupmenu_field(h_fig,h,fnames{i},val,lbl_pos,ud,dflt_val);
      end

   elseif (isstruct(val))
      if (isfield(ud.units,fnames{i}))
         sub_units = getfield(ud.units,fnames{i});
      else
         if (isfield(ud.orig_def,fnames{i}))
            [dummy sub_units] = split_def(getfield(ud.orig_def,fnames{i}));
         else
            sub_units = struct([]);
         end
      end
      ud = reset_sub_struct_field(h_fig,h,fnames{i},val,lbl_pos,ud,dflt_val,sub_units);
   end
   if (isempty(h) | ~ishandle(h))  % h did not exist before. Now it is!
      % AF 12/14/2004 don't disable pushbuttons (for uigetfile).
      % h = findobj(h_fig,'Tag',fnames{i});
      h = findobj(h_fig,'Tag',fnames{i},'-not','Style','pushbutton');
      if (isfield(ud.protected,fnames{i}))
         set(h,'Enable',    'off');
         cmenu = get(h,'UIContextMenu');
         if (iscell(cmenu))
            cmenu = unique([cmenu{:}]);
         end
         for hi = 1:length(cmenu)
            item = uimenu(cmenu(hi), ...
               'Label',         'Unlock', ...
               'Separator',     'on', ...
               'Tag',           [fnames{i} '_UnLock'], ...
               'Callback',      ['StructDlg(''unlock(' fnames{i} ')'')'] );
         end
      end
   end
end
set(h_fig,'UserData',ud);
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = auto_update(fnames,ud,hfig,ignore_defaults)
for i = 1:length(fnames)
   AU = getfield(ud.auto_update,fnames{i});
   if (~isempty(AU))
      old_vals = ud.vals;
      for i = 1:length(AU)
         ud = set_fields_ui(ud.orig_def,hfig,ud,[],AU(i),ignore_defaults);
      end
      blink_auto_changes(AU, old_vals, ud.vals, hfig)
   end
end
return;

%%%%%%%%%%%%%%%%%
function blink_auto_changes(AU_fnames, old_vals, new_vals, hfig)
blink_period = 0.2;
h = NaN*zeros(1,length(AU_fnames));
col = cell(1,length(AU_fnames));
enbl = cell(1,length(AU_fnames));
for i = 1:length(AU_fnames)
   oldval = getfield(old_vals,AU_fnames{i});
   val    = getfield(new_vals,AU_fnames{i});
   if (~all(isnan(oldval)) & ((xor(isempty(oldval),isempty(val)) | any(size(oldval)~= size(val)) | oldval ~= val)))
      h(i) = findobj(hfig,'Tag',AU_fnames{i});
      col{i} = get(h(i),'ForegroundColor');
      enbl{i} = get(h(i),'Enable');
   end
end
reps = 2;
do_wait = 0;
for j = 1:reps
   for i = 1:length(AU_fnames)
      if (ishandle(h(i)))
         set(h(i),'enable','on');
         set(h(i),'ForegroundColor',[0 0.8 .4]);
         do_wait = 1;
      end
   end
   if (do_wait)
      drawnow;
      timer(blink_period);
   end
   for i = 1:length(AU_fnames)
      if (ishandle(h(i)))
         set(h(i),'Enable',enbl{i});
         set(h(i),'ForegroundColor',col{i});
      end
   end
   if (do_wait & j < reps)
      drawnow;
      timer(blink_period);
   end
end
drawnow;
return;

%%%%%%%%%%%%%%%%%
function ud = register_undo_info(fnames,vals,ud,h_fig)
for i = 1:length(fnames)
   prev_undo = getfield(ud.undo_vals,fnames{i});
   if (~strcmp(vals{i},'NaN') & ((xor(isempty(prev_undo),isempty(vals{i})) | strcmp(prev_undo,vals{i})==0)))
      ud.undo_vals = setfield(ud.undo_vals,fnames{i},vals{i});
      h_undo = findobj(h_fig,'Tag',[fnames{i} '_UNDO']);
      if (isempty(vals{i}))
         set(h_undo,'Enable','off');
      else
         set(h_undo,'Enable','on');
      end
   end
end
return

%%%%%%%%%%%%%%%%%
function undoCB(f,h_fig)
ud = get(h_fig,'Userdata');
undo_val = getfield(ud.undo_vals,f);
if (~isempty(undo_val))
   if (~ischar(undo_val))
      undo_val = mat2str(undo_val);
   end
   h = findobj(h_fig,'Tag',f);
   set(h,'String',undo_val);
   h_undo = findobj(h_fig,'Tag',[f '_UNDO']);
   set(h_undo,'Enable','off');
end
return

%%%%%%%%%%%%%%%%%
function unlockCB(f,h_fig)
h = findobj(h_fig,'Tag',f);
for i = 1:length(h)
   set(h,'Enable','on');
end
set (gcbo,'Enable','off');
return;

%%%%%%%%%%%%%%%%%
function ud = prepare2evaluate(str,f,h,ud)
self_ref = struct_mfile_reference('','this',{str});
if (isempty(self_ref))
   return;
end
self_fields = fieldnames(self_ref);
if (~isempty(self_fields))
   h_fig = get(h,'Parent');
   ud.vals = setfield(ud.vals,f,NaN);
   set(h_fig,'Userdata',ud); % Prevent recursive loops when the user does stupid things.
   for i = 1:length(self_fields)
      if (isfield(ud.def,self_fields{i}) & ~isfield(ud.vals,self_fields{i}))
         % If the refered field was not set yet, NaN it. it will be evaluated later.
         ud.vals = setfield(ud.vals,self_fields{i},NaN);
      end
      cur_AU = getfield(ud.auto_update,self_fields{i});
      if (isempty(cur_AU)) %% AF 11/22/04 R14
         cur_AU = {};
      end
      if (isempty(strmatch(f,cur_AU,'exact')) & ~strcmp(self_fields{i},f))
         ud.auto_update = setfield(ud.auto_update,self_fields{i},cat(1,cur_AU,{f}));
      end
   end
end
return

%%%%%%%%%%%%%
% Protect other variables from the evaluation results, and passing 'this' as a parameter
function retval = secure_eval(this,str)
retval = eval(['[' str ']']);
return

%%%%%%%%%%%%%
function [ud,str] = checkNset_numeric_field(h,f,limits,ud,undo_val,dflt_val,ignore_defaults)
col   = ud.col;
str = get(h,'String');
h_fig = get(h,'Parent');
try
   iserror = 0;
   ud = prepare2evaluate(str,f,h,ud);
   if (isempty(dflt_val))
      retval = secure_eval(ud.vals,str);
   else
      retval = dflt_val;
   end
   if (~isnumeric(retval))
      str = 'Numbers only!';
      iserror = 1;
   elseif (any(retval(:) < limits(1) | retval(:) > limits(2)))
      str = ['Allowed range: [' num2str(limits) ']'];
      iserror = 1;
   else
      str    = mat2str(retval);
   end
catch
   iserror = 1;
   str     = strrep(lasterr,char(10),': ');
end
if (iserror)
   ud.error = setfield(ud.error,f,1);
   retval = [];
   col = 'r';
elseif (isfield(ud.error,f))
   ud.error = rmfield(ud.error,f);
   if (isempty(fields(ud.error)))
      ud.error = [];
   end
end
set(h,'String',str);
set(h,'ForegroundColor',col);
ud = register_undo_info({f},{undo_val},ud,h_fig);
ud.vals = setfield(ud.vals,f,retval);
if (~iserror)
   ud = auto_update({f},ud,h_fig,ignore_defaults);
end
return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function update_uicontrol_width(h,width)
hud = get(h,'UserData');
if ((isfield(hud,'related_h')) & (ishandle(hud.related_h)))
   related_h = hud.related_h;
   related_pos = get(related_h,'Position');
   related_width = related_pos(3);
else
   related_h = [];
   related_width = 0;
end
fig_pos = get(get(h,'Parent'),'Position');
pos = get(h,'Position');
fig_width = fig_pos(3);
width = min(width, fig_width-related_width-pos(1)-1);
width_change = width - pos(3);
pos(3) = width;
set(h,'Position',pos);
if (~isempty(related_h))
   related_pos(1) = related_pos(1) + width_change;
   set(related_h,'Position',related_pos);
end
return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implemetation of Numeric field (including function evaluation)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_numeric_field(h_fig,h,f,val,lbl_pos,limits,ud,dflt_val, ignore_defaults)
strval = val;
if (~ischar(strval))
   strval = mat2str(strval);
end
if (isempty(h))
   prev_str = '';
   if (length(strval) > 60)
      item_label = ['Reset (to: ''' strval(1:60) '...'')'];
   else
      item_label = ['Reset (to: ''' strval ''')'];
   end
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',     item_label, ...
      'Callback',  ['StructDlg(''reset(' f ')'')'] );
   item2 = uimenu(cmenu, ...
      'Label',     'Undo', ...
      'Enable',    'off', ...
      'Separator', 'off', ...
      'Tag',       [f '_UNDO'], ...
      'Callback',  ['StructDlg(''undo(' f ')'')'] );

   h = uicontrol(h_fig, ...
      'style',      'edit', ...
      'Units',      'char', ...
      'position',   [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2) 20 1.5],...
      'string',     [], ...
      'FontName',   'Helvetica', ...
      'FontSize',   9, ...
      'BackgroundColor', [1 1 1], ...
      'TooltipString', ['Allowed range: [' num2str(limits) ']'], ...
      'horizon',    'left', ...
      'Tag',        f, ...
      'UIContextMenu', cmenu, ...
      'Callback',   ['StructDlg({''' f '''});']);
   set(item2,'Userdata',struct('uicontrol',h));
   if (ischar(val))
      h1 = uicontrol(h_fig, ...
         'style',            'text', ...
         'units',            'char', ...
         'position',         [lbl_pos(3)+lbl_pos(1)+0.5+21.5 lbl_pos(2) length(val)+10 1.5],...
         'String',           ['=(''' val ''')'], ...
         'FontName',         'Helvetica', ...
         'fontsize',         9, ...
         'ForegroundColor',  [0.15 0.15 0.15], ...
         'FontWeight',       'light', ...
         'FontAngle',        'normal', ...
         'Tag',              '', ...
         'horizon',          'left');
      set(h,'UserData', struct('related_h',h1));
   end
end
prev_str = get(h,'String');
set(h,'String',strval);
[ud,str] = checkNset_numeric_field(h,f,limits,ud,prev_str,dflt_val,ignore_defaults);
% fprintf('reset_numeric_field: ''%s'': %s -> %s\n', f, strval, str);
update_uicontrol_width(h,length(str)+10);
return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implementation of Open String field
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_char_field(h_fig,h,f,val,lbl_pos,ud);
ud.vals = setfield(ud.vals,f,val);
if (isempty(h))
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',     ['Reset (to: ''' val ''')'], ...
      'Callback',  ['StructDlg(''reset(' f ')'')'] );

   h = uicontrol(h_fig, ...
      'style',      'edit', ...
      'Units',      'char', ...
      'position',   [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2) 20 1.5],...
      'string',     [], ...
      'FontName',   'Helvetica', ...
      'FontSize',   9, ...
      'horizon',    'left', ...
      'BackgroundColor', [1 1 1], ...
      'Tag',        f, ...
      'UIContextMenu', cmenu, ...
      'Callback',   ['StructDlg({''' f '''});']);
end
set(h,'String',val);
pos = get(h,'Position');
pos(3) = max(20,length(val)+10);
set(h,'Position',pos);
set(h,'ForegroundColor',ud.col);
return
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implemenation of Radio Buttons
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_radio_field(h_fig,h,f,val,lbl_pos,ud,sep,dflt_val)
selected = 1;
sep = [0 sep length(val)+1];
options = cell(1,length(sep)-1);
if (isempty(h))
   h = NaN*zeros(1,length(options));
end
selected = zeros(1,length(options));
selected_str = '';
setval = '';
for sep_i = 1:length(sep)-1
   options{sep_i} = val(sep(sep_i)+1:sep(sep_i+1)-1);
   if ((~isempty(options{sep_i})) & (options{sep_i}(1) == '{' & options{sep_i}(end) == '}'))
      options{sep_i} = options{sep_i}(2:end-1);
      selected(sep_i) = 1;
      selected_str = options{sep_i};
      setval = str2double(options{sep_i});
      if (isnan(setval))
         setval = options{sep_i};
      end
   end
end
ud.vals = setfield(ud.vals,f,setval);
if (~isempty(dflt_val))
   if (isnumeric(dflt_val))
      dflt_val = num2str(dflt_val);
   end
   dflt_selected = strmatch(dflt_val,options,'exact');
   if (~isempty(dflt_selected))
      ud.vals = setfield(ud.vals,f,dflt_val);
      selected = zeros(1,length(options));
      selected(dflt_selected) = 1;
      selected_str = options{dflt_selected};
   end
end
sum_width = 0;
for val_i = 1:length(options)
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',     ['Reset (to: ''' selected_str ''')'], ...
      'Callback',  ['StructDlg(''reset(' f ')'')'] );

   if (~ishandle(h(val_i)))
      width = min(35, 10+length(options{val_i}));
      h(val_i) = uicontrol(h_fig, ...
         'style',          'radio', ...
         'Units',          'char', ...
         'position',       [lbl_pos(3)+lbl_pos(1)+0.5+sum_width lbl_pos(2) width 1.5],...
         'string',         options{val_i}, ...
         'FontName',       'Helvetica', ...
         'FontSize',       9, ...
         'horizon',        'left', ...
         'Value',          selected(val_i), ...
         'Tag',            f, ...
         'UIContextMenu',  cmenu, ...
         'Callback',       ['StructDlg({''' f '''});']);
      sum_width = sum_width + width;
   else
      if (strcmp(get(h(val_i),'String'), selected_str))
         set(h(val_i),'Value',     1);
      else
         set(h(val_i),'Value',     0);
      end
   end
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implementation of Getfile, Putfile and Getdir
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_getfile_field(h_fig,h,f,val,lbl_pos,ud,dflt_val)
lpar = min(findstr(val{1}, '('));
first_comma = min(findstr(val{1}, ','));
rpar = max(findstr(val{1}, ''')'));
end_filter_spec = min([first_comma rpar+1]);
l_curl = min(findstr(val{1}, '{'));
r_curl = min(findstr(val{1}, '}'));
extra_args = '';
filter_spec = '';
if (~isempty(dflt_val))
   filter_spec = dflt_val;
elseif (~isempty(lpar))
   if (~isempty(end_filter_spec))
      if (~isempty(l_curl) & ~isempty(r_curl)) % Note, there is no check that the curls are smaller than end_filter_spec
         filter_spec = val{1}(l_curl:r_curl); % Must contain the curly brackets.
      else
         filter_spec = val{1}(lpar+2:end_filter_spec-2);
      end
      if (~isempty(first_comma))
         extra_args = val{1}(first_comma+1:rpar);
      end
   end
else
   lpar = length(val{1});
end
if (filter_spec(1) == '{') % if the filter is a complex set of filters then don't present it.
   filter_label = ['Files of types: ' filter_spec];
else
   filter_label = filter_spec;
   filter_spec = '';
end
cmd = deblank(val{1}(1:lpar-1));
width = max(20,length(filter_label)+10);
if (isempty(h))
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',         ['Reset (to: ''' filter_label ''')'], ...
      'Callback',      ['StructDlg(''reset(' f ')'')'] );

   h = [0 0];
   h(2) = uicontrol(h_fig, ...
      'style',          'edit', ...
      'Units',          'char', ...
      'position',       [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2) width 1.5],...
      'string',         filter_label, ...
      'FontName',       'Helvetica', ...
      'FontSize',       9, ...
      'horizon',        'left', ...
      'BackgroundColor', [1 1 1], ...
      'Tag',            f, ...
      'UIContextMenu',  cmenu, ...
      'Callback',       ['StructDlg({''' f '''});']);
   h(1) = uicontrol(h_fig, ...
      'style',          'pushbutton', ...
      'Units',          'char', ...
      'position',       [lbl_pos(3)+lbl_pos(1)+0.5+width+0.5 lbl_pos(2)  3  1.5], ...
      'string',         char(133), ...
      'FontName',       'Helvetica', ...
      'FontSize',       9, ...
      'Tag',            f, ...
      'UIContextMenu',  cmenu, ...
      'callback',       ['StructDlg({''' f '''});']);

   push_ud.cmd    = cmd;
   push_ud.params = h(2);
   push_ud.filter_spec = filter_spec;
   push_ud.varargin = extra_args;
   set(h(1),'Userdata',push_ud);
   set(h(2),'Userdata', struct('related_h', h(1)));
end
str_h = findobj(h, 'style', 'edit');
set(str_h,'string',filter_label);
update_uicontrol_width(str_h,width);
ud.vals = setfield(ud.vals,f,filter_label);
% ud.def = setfield(ud.def,f,filter_spec);
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implemenation of Binary Check Box
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_checkbox_field(h_fig,h,f,val,h_lbl,lbl_pos,ud,dflt_val)
if ((~isempty(dflt_val)) & (dflt_val == 0 | dflt_val == 1))
   selected = dflt_val;
else
   selected = min(strmatch('{',val)) - 1;
   if (isempty(selected))
      selected = 0;
   end
end
if (isempty(h))
   if (selected)
      opt_label = 'Checked';
   else
      opt_label = 'UnChecked';
   end
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',         ['Reset (to: ''' opt_label ''')'], ...
      'Callback',      ['StructDlg(''reset(' f ')'')'] );

   h = uicontrol(h_fig, ...
      'style',          'checkbox', ...
      'Units',          'char', ...
      'position',       [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2) 2 1.5],...
      'string',         'test', ...
      'horizon',        'left', ...
      'value',          selected, ...
      'Tag',            f, ...
      'UIContextMenu',  cmenu, ...
      'Callback',       ['StructDlg({''' f '''});']);
end
set(h, 'value',      selected);
lbl_str = get(h_lbl,'String');
lbl_str(end) = '?';
set(h_lbl,'String',lbl_str);
ud.vals = setfield(ud.vals,f,selected);
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Implemenation of popupmenu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_popupmenu_field(h_fig,h,f,val,lbl_pos,ud,dflt_val)
selected = 1;
for val_i = 1:length(val)
   if (val{val_i}(1) == '{' & val{val_i}(end) == '}')
      val{val_i} = val{val_i}(2:end-1);
      selected = val_i;
   end
end
setval = str2double(val{selected});
if (isnan(setval))
   setval = val{selected};
end
ud.vals = setfield(ud.vals,f,setval);
if (~isempty(dflt_val))
   if (isnumeric(dflt_val))
      dflt_val = num2str(dflt_val);
   end
   dflt_selected = strmatch(dflt_val,val,'exact');
   if (~isempty(dflt_selected))
      ud.vals = setfield(ud.vals,f,dflt_val);
      selected = dflt_selected;
   end
end
if (isempty(h))
   opt_label = getfield(ud.vals,f);
   if (isnumeric(opt_label))
      opt_label = num2str(opt_label);
   end
   cmenu = uicontextmenu;
   item1 = uimenu(cmenu, ...
      'Label',         ['Reset (to: ''' opt_label ''')'], ...
      'Callback',      ['StructDlg(''reset(' f ')'')'] );

   width = size(char(val),2) + 10;
   h = uicontrol(h_fig, ...
      'style',      'popupmenu', ...
      'Units',      'char', ...
      'position',   [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2) width 1.5],...
      'string',     val, ...
      'FontName',   'Helvetica', ...
      'FontSize',   9, ...
      'horizon',    'left', ...
      'BackgroundColor', [1 1 1], ...
      'Value',      selected, ...
      'Tag',        f, ...
      'UIContextMenu',  cmenu, ...
      'Callback',   ['StructDlg({''' f '''});']);
else
   set(h,'Value',  selected);
end
return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%s
%% Implemenation of recursive call (for sub-structures)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = reset_sub_struct_field(h_fig,h,f,val,lbl_pos,ud,dflt_val,units);
if (isfield(ud.vals,f));
   [sub_vals,sub_units] = StructDlg(val,'',getfield(ud.vals,f),[],'off');
else
   [sub_vals,sub_units] = StructDlg(val,'',dflt_val,[],'off');
end
ud.vals  = setfield(ud.vals,f,sub_vals);
ud.units = setfield(ud.units,{1},f,sub_units);
tooltipstr = struct_tooltip(sub_vals,units);
if (isempty(h))
   h = uicontrol(h_fig, ...
      'style',          'pushbutton', ...
      'Units',          'char', ...
      'position',       [lbl_pos(3)+lbl_pos(1)+0.5 lbl_pos(2)  3  1.5], ...
      'string',         char(187), ...
      'FontName',       'Helvetica', ...
      'FontSize',       9, ...
      'Tag',            f, ...
      'TooltipString',  tooltipstr, ...
      'callback',       ['StructDlg({''' f '''});']);

   push_ud.cmd    = 'StructDlg';
   push_ud.params = units; % units are specified here for the tooltip string only
   set(h,'Userdata',push_ud);
end
return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  MAIN CALL_BACK FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%
function StructDlgCB(f)
%
hgcbf = gcbf;
ud    = get(hgcbf,'UserData');
width = ud.width;
def   = getfield(ud.def,f);
v     = getfield(ud.vals,f);
hgcbo = gcbo;
if (isfield(ud.limits,f))
   limits = getfield(ud.limits,f);
else
   limits = [];
end
undo_flag = 0;
if (strcmp(get(hgcbo,'Type'), 'uimenu'))
   hgcbo = getfield(get(hgcbo,'Userdata'),'uicontrol');
   prev_val = '';
else
   prev_val = v;
end
switch (get(hgcbo,'Style'))
   case 'edit'
      if (~isempty(limits) & isnumeric(limits))
         [ud,str] = checkNset_numeric_field(hgcbo,f,limits,ud,prev_val,[],1);
      elseif (ischar(def))
         str = get(hgcbo,'String');
         width = length(str)+10;
         ud.vals = setfield(ud.vals,f,str);
      elseif (iscell(def)) %% special commands' edit window
         str = get(hgcbo,'String');
         retval = str2num(str);
         if (isempty(retval))
            retval = str;
         end
         ud.vals = setfield(ud.vals,f,retval);
      end
      update_uicontrol_width(hgcbo,length(str)+10)

   case 'popupmenu'
      val = get(hgcbo,'Value');
      str = def{val};
      if (str(1) == '{')
         str = str(2:end-1);
      end
      setval = str2double(str);
      if (isnan(setval))
         setval = str;
      end
      ud.vals = setfield(ud.vals,f,setval);

   case 'radiobutton'
      str = get(hgcbo,'String');
      h = findobj(hgcbf,'Tag',get(hgcbo,'Tag'));
      for h_i = 1:length(h)
         if (~strcmp(str,get(h(h_i),'String')))
            set(h(h_i),'Value',0);
         end
      end
      setval = str2double(str);
      if (isnan(setval))
         setval = str;
      end
      ud.vals = setfield(ud.vals,f,setval);

   case 'checkbox'
      val = get(hgcbo,'Value');
      ud.vals = setfield(ud.vals,f,val);

   case 'pushbutton'
      push_ud = get(hgcbo,'Userdata');
      switch (push_ud.cmd)
         case {'uigetfile','uiputfile','uigetdir'}
            if (~isempty(push_ud.filter_spec))
               filter_spec = push_ud.filter_spec;
            else
               filter_spec = get(push_ud.params,'String');
            end
            extra_args = push_ud.varargin;
            if (isempty(filter_spec))
               filter_spec = '*.*';
            end
            if (filter_spec(1) ~= '{' & filter_spec(1) ~= '''')
               filter_spec = ['''' filter_spec ''''];
            end
            if (~isempty(extra_args))
               extra_args = [',' extra_args];
            end
            if (strcmp(push_ud.cmd,'uigetdir'))
               eval(['fname = ' push_ud.cmd '(' filter_spec  extra_args ');'])
               pname = '';
            else
               eval(['[fname, pname] = ' push_ud.cmd '(' filter_spec  extra_args ');'])
            end
            return_val = '';
            str = '';
            if (~isempty(fname) & (iscell(fname) | fname ~= 0))
               if (isstr(fname))
                  str = [pname fname];
                  return_val = str;
               elseif (iscell(fname))
                  return_val = cell(1,length(fname));
                  return_val{1} = [pname fname{1}];
                  str = [pname '{' fname{1}];
                  for fname_i = 2:length(fname)
                     str = [str ', ' fname{fname_i}];
                     return_val{fname_i} = [pname fname{fname_i}];
                  end
                  str = [str '}'];
               end
               % In case multi-files were chosen, save the current filter spec.
               if (isempty(push_ud.filter_spec) & iscell(fname))
                  push_ud.filter_spec = filter_spec;
                  set(hgcbo,'Userdata',push_ud);
               end
               ud.vals = setfield(ud.vals,f,return_val);
               set(push_ud.params,'String',str);
               width = length(str)+14;
               update_uicontrol_width(push_ud.params, width)
            end

         case 'StructDlg'
            if (isempty(ud.error))
               title = [get(hgcbf,'Name') '->' f];
               if (isfield(ud.dflt,f))
                  dflt_val = getfield(ud.dflt,f);
               else
                  dflt_val = [];
               end
               if (isfield(ud.limits,f))
                  limits = getfield(ud.limits,f);
               else
                  limits = [];
               end
               if (ud.specified_pos)
                  fig_pos = get(hgcbf,'Position');
                  screen_size  = get_screen_size('char');
                  aspec_ratio  = screen_size(3)/screen_size(4);
                  recurssion_offset = 5;
                  rec_pos = [fig_pos(1)+recurssion_offset  fig_pos(2)-recurssion_offset/aspec_ratio fig_pos(3:4)];
               else
                  rec_pos = [];
               end
               ret_struct = StructDlg(getfield(ud.orig_def,f),title,dflt_val,rec_pos,'on',v);
               tooltipstr = struct_tooltip(ret_struct,push_ud.params);
               set(hgcbo,'TooltipString', tooltipstr);
               ud.vals = setfield(ud.vals,f,ret_struct);
            else
               beep;
            end
      end
end
ud = auto_update({f},ud,hgcbf,1);% AF 1/10/2005: Update fields that reference f
set(hgcbf,'UserData',ud);
return;


function channel_loc2tvs

% start at the root and convert the channel_loc.txt files for BIDS
% SPM12 dependency

folders = dir('sub*')
for f=7:length(folders)
    cd(folders(f).name)
    file = dir('*.txt')
    fileID = fopen(file.name);
    C = textscan(fileID,'%d %f32 %f32 %f32 %s %s');
    fclose(fileID);

    % do the electrodes.tsv
    clear name
    for i=1:74
        name(i,:) = cell2mat(C{5}(i));
    end
    x = C{2}(1:74);
    y = C{3}(1:74);
    z = C{4}(1:74);
    T = table(name,x,y,z);
    writetable(T,[pwd filesep 'eeg' filesep folders(f).name '_task-facerecognition_electrodes.txt'],'Delimiter','\t')
    movefile([pwd filesep 'eeg' filesep folders(f).name '_task-facerecognition_electrodes.txt'],[pwd filesep 'eeg' filesep folders(f).name '_task-facerecognition_electrodes.tsv'])

    % do the electrodes.json
    json = struct('EEGCoordinateSystem','T1w', ...
        'EEGCoordinateUnits','mm','IntendedFor',['anat' filesep folders(f).name '_T1w.nii.gz']);
    spm_jsonwrite(['eeg' filesep folders(f).name '_task-facerecognition_electrodes.json'],json,struct('indent','  '))

    % do the fid.json
    json = struct(...
        'EEGCoordinateSystem','T1w', ...
        'EEGCoordinateUnits', 'mm', ...
        'AnatomicalMRICoordinateSystem', 'T1w', ...
        'AnatomicalMRICoordinateUnits', 'mm', ...
        'LandmarkCoordinates', ' ', ...
        'LandmarkCoordinateSystem','T1w', ...
        'LandmarkCoordinateUnits','mm');

    clear name
    for i=75:77
        tmp = cell2mat(C{5}(i));
        name(i-74,:) = tmp(1:3);
    end
        json.LandmarkCoordinates = ['{"' name(1,:) '":[' num2str(double([C{2}(75),C{3}(75),C{4}(75)])) '], "' ...
       name(2,:) '":[' num2str(double([C{2}(76),C{3}(76),C{4}(76)])) '], "' ...
        name(3,:) '":[' num2str(double([C{2}(77),C{3}(77),C{4}(77)])) ']}'];

    spm_jsonwrite(['eeg' filesep folders(f).name '_task-facerecognition_fid.json'],json,struct('indent','  '))

    % clean up
    delete(file.name)
    cd ..
end


function FVToolStartUp()
%
% SYNOPSIS:
%   FVToolStartUp()
%
% PARAMETERS:
%   No perameter
%
% RETURNS:
%   None
%
% EXAMPLE:
%   n.a.
%
% SEE ALSO:
%   PVTinitialize, FVTdemo

%{
Copyright (c) 2012-2021 Ali Akbar Eftekhari
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:

    *   Redistributions of source code must retain the above copyright notice,
        this list of conditions and the following disclaimer.
    *   Redistributions in binary form must reproduce the above
        copyright notice, this list of conditions and the following
        disclaimer in the documentation and/or other materials provided
        with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%}
try
p = mfilename('fullpath');
file_name = mfilename;
current_path = p(1:end-1-length(file_name));
addpath([current_path '/Boundary']);
addpath([current_path '/Calculus']);
addpath([current_path '/Classes']);
addpath([current_path '/Discretization']);
addpath([current_path '/MeshGeneration']);
addpath([current_path '/Solvers']);
addpath([current_path '/Utilities']);
addpath([current_path '/Visualization']);
addpath([current_path '/Examples']);
addpath([current_path '/Physics']);
addpath([current_path '/Tests']);

try
    addpath([current_path '/PhysicalProperties']);
    addpath([current_path '/FieldGeology']);
catch
    disp(['Some of the physical functions are not available in this copy.' ...
    ' It does not affect the functionality of the FVMtool']);
end

% Check for other solvers
    % check for AGMG availability
    cd(current_path);
    cd('Solvers');
    if exist('AGMG_3.2', 'dir') == 7
        addpath([pwd '/AGMG_3.2']);
        disp('AGMG 3.2 linear solver is available.');
    elseif exist('AGMG_3.0', 'dir') == 7
        addpath([pwd '/AGMG_3.0']);
        disp('AGMG 3.0 linear solver is available.');
    else
        disp('AGMG 3.x linear solver is NOT available (Not necessary).');
    end
    % check for Factorize availability
    if exist('Factorize', 'dir') == 7
        addpath([pwd '/Factorize']);
        disp('Factorize is available.');
    end
    cd(current_path);
% end of check for other solvers

% Check for the PVT package
if exist('PVTtoolbox', 'dir') == 7
    addpath([current_path '/PVTtoolbox']);
    if exist('PVTinitialize', 'file') == 2
        cd('PVTtoolbox');
        PVTinitialize();
        cd(current_path);
        disp('PVTtoolbox has started successfully.');
    else
        disp('PVTtoolbox is found but cannot be initialized.');
    end
else
    disp('PVTtoolbox is NOT available (Not necessary).');
end
disp('FiniteVolumeToolbox has started successfully.');
catch err
    error('An error occured while tryng to start the FiniteVolumeToolbox.')
end


function varargout=upolyhedron(varargin)
%
% For calling details please see v_upolyhedron.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_upolyhedron.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: upolyhedron.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_upolyhedron(varargin{:});
else
    v_upolyhedron(varargin{:});
end


classdef TestBlender
    %TestBlender

    methods (Static)
        function test_1
            btypes = {'FeatherBlender', 'MultiBandBlender'};
            for i=1:numel(btypes)
                obj = cv.Blender(btypes{i});
                typename = obj.typeid();
                validateattributes(typename, {'char'}, {'row', 'nonempty'});

                %{
                %TODO
                obj.prepare(corners, sizes);
                obj.feed(img, mask, tl);
                [dst, dst_mask] = obj.blend();
                %}
            end
        end
    end

end


function varargout = SCARA_GUI(varargin)
% SCARA_GUI M-file for SCARA_GUI.fig
%      SCARA_GUI, by itself, creates a new SCARA_GUI or raises the existing
%      singleton*.
%
%      H = SCARA_GUI returns the handle to a new SCARA_GUI or the handle to
%      the existing singleton*.
%
%      SCARA_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in SCARA_GUI.M with the given input arguments.
%
%      SCARA_GUI('Property','Value',...) creates a new SCARA_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before SCARA_GUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to SCARA_GUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help SCARA_GUI

% Last Modified by GUIDE v2.5 26-Aug-2012 15:11:43

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @SCARA_GUI_OpeningFcn, ...
                   'gui_OutputFcn',  @SCARA_GUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before SCARA_GUI is made visible.
function SCARA_GUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to SCARA_GUI (see VARARGIN)

% Choose default command line output for SCARA_GUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes SCARA_GUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
view(SCARA28);

dist=-get(handles.slider5,'value');
y1=-.5*dist;
y2=.5*dist;
SCARA28.EndV1.translation = [-.35, y1, 0];
SCARA28.EndV2.translation = [-.35, y2, 0];

d4=-get(handles.slider4,'value');
SCARA28.d4b.translation=[0,d4,0];

T4=get(handles.slider3,'value');
SCARA28.d4b.rotation = [0, 1, 0,T4*pi/180];

T2=-get(handles.slider2,'value');
SCARA28.a2.rotation = [1, 0, 0, T2*pi/180];

T1=get(handles.slider1,'value');
SCARA28.d1.rotation = [0, 1, 0, T1*pi/180];
clc
% --- Outputs from this function are returned to the command line.
function varargout = SCARA_GUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of
%        slider

SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
T1=get(handles.slider1,'value');
if T1==360
   set(handles.slider1,'value',0);
end
SCARA28.d1.rotation = [0, 1, 0, T1*pi/180];

% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function slider2_Callback(hObject, eventdata, handles)
% hObject    handle to slider2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
T2=-get(handles.slider2,'value');
SCARA28.a2.rotation = [1, 0, 0, T2*pi/180];

% --- Executes during object creation, after setting all properties.
function slider2_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function slider3_Callback(hObject, eventdata, handles)
% hObject    handle to slider3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
T4=get(handles.slider3,'value');
if T4==360
   set(handles.slider3,'value',0);
end
SCARA28.d4b.rotation = [0, 1, 0,T4*pi/180];

% --- Executes during object creation, after setting all properties.
function slider3_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function slider4_Callback(hObject, eventdata, handles)
% hObject    handle to slider4 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
d4=-get(handles.slider4,'value');
SCARA28.d4b.translation=[0,d4,0];

% --- Executes during object creation, after setting all properties.
function slider4_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider4 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function slider5_Callback(hObject, eventdata, handles)
% hObject    handle to slider5 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
dist=-get(handles.slider5,'value');
y1=-.5*dist;
y2=.5*dist;
SCARA28.EndV1.translation = [-.35, y1, 0];
SCARA28.EndV2.translation = [-.35, y2, 0];

% --- Executes during object creation, after setting all properties.
function slider5_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider5 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --------------------------------------------------------------------
function File_tag_Callback(hObject, eventdata, handles)
% hObject    handle to File_tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function Edit_tag_Callback(hObject, eventdata, handles)
% hObject    handle to Edit_tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function Reset_tag_Callback(hObject, eventdata, handles)
% hObject    handle to Reset_tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
SCARA28 = vrworld('SCARA28.wrl');
open(SCARA28)
dist=-1.3;
y1=-.5*dist;
y2=.5*dist;
SCARA28.EndV1.translation = [-.35, y1, 0];
SCARA28.EndV2.translation = [-.35, y2, 0];
d4=0;
SCARA28.d4b.translation=[0,d4,0];
T4=0;
SCARA28.d4b.rotation = [0, 1, 0,T4*pi/180];
T2=0;
SCARA28.a2.rotation = [1, 0, 0, T2*pi/180];
T1=0;
SCARA28.d1.rotation = [0, 1, 0, T1*pi/180];
clc

set(handles.slider5,'value',-dist);
set(handles.slider4,'value',0);
set(handles.slider3,'value',0);
set(handles.slider2,'value',0);
set(handles.slider1,'value',0);

% --------------------------------------------------------------------
function About_us_tag_Callback(hObject, eventdata, handles)
% hObject    handle to About_us_tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

about_us

% --- Executes during object creation, after setting all properties.
function figure1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% --------------------------------------------------------------------
function Exit_Tag_Callback(hObject, eventdata, handles)
% hObject    handle to Exit_Tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


function h=plotbox(box,varargin)
% PLOTBOX Plots box(es) to the current figure.
%
% Synopsis:
%  h=plotbox(box)
%  h=plotbox(box,plot_arguments)
%
% Input:
%  box [4 x numOfBoxes] box coordinates when each column has the format
%    [top_left_col top_left_row bottom_right_col bottom_right_row]
%
%  plot_arguments [...] agruments passed to plot fuction.
%
% Output:
%  h [4 x numOfBoxes] hnadles to lines forming the boxes.
%
%

if nargin < 2
    line_style = {'b'};
else
    line_style= varargin;
end

current_ishold = ishold;
hold on;

if min(size(box)) == 1

    h = [0 0 0 0]';
    h(1)=plot([box(1) box(1)],[box(2) box(4)],line_style{:});
    h(2)=plot([box(3) box(3)],[box(2) box(4)],line_style{:});
    h(3)=plot([box(1) box(3)],[box(2) box(2)],line_style{:});
    h(4)=plot([box(1) box(3)],[box(4) box(4)],line_style{:});
else
    if size(box,1) ~= 4
        box = box';
    end

    h=[];
    for i=1:size(box,2)
        h = [h plotbox(box(:,i),line_style{:})];
    end
end

if ~current_ishold
    hold off;
end

%EOF


function ft = f03_title ( )

%*****************************************************************************80
%
%% F03_TITLE returns the title for function 3.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string FT, the function title.
%
  ft = 'Saddle';

  return
end


%  Save back to the back to the original image a portion of slices that
%  were loaded by "load_untouch_nii". You can process those slices matrix
%  in any way, as long as their dimension is not changed.
%
%  Usage: save_untouch_slice(slice, filename, ...
%		slice_idx, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx])
%
%  Example:
%	nii = load_nii('avg152T1_LR_nifti.nii');
%	save_nii(nii, 'test.nii');
%	view_nii(nii);
%	nii = load_untouch_nii('test.nii','','','','','',[40 51:53]);
%	nii.img = ones(91,109,4)*122;
%	save_untouch_slice(nii.img, 'test.nii', [40 51:52]);
%	nii = load_nii('test.nii');
%	view_nii(nii);
%
%  - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
%
function save_untouch_slice(slice, filename, slice_idx, img_idx, dim5_idx, dim6_idx, dim7_idx)

   if ~exist('filename','var') | ~exist('slice_idx','var')
      error('Usage: save_untouch_slice(slice, filename, slice_idx, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx])');
   end

   if ~exist('img_idx','var') | isempty(img_idx)
      img_idx = [];
   end

   if ~exist('dim5_idx','var') | isempty(dim5_idx)
      dim5_idx = [];
   end

   if ~exist('dim6_idx','var') | isempty(dim6_idx)
      dim6_idx = [];
   end

   if ~exist('dim7_idx','var') | isempty(dim7_idx)
      dim7_idx = [];
   end

   %  Read the dataset header
   %
   [nii.hdr,nii.filetype,nii.fileprefix,nii.machine] = load_nii_hdr(filename);

   if nii.filetype == 0
      nii.hdr = load_untouch0_nii_hdr(nii.fileprefix,nii.machine);
   else
      nii.hdr = load_untouch_nii_hdr(nii.fileprefix,nii.machine,nii.filetype);
   end

   %  Save the dataset body
   %
   save_untouch_slice_img(slice,filename,nii.hdr,nii.filetype,nii.fileprefix, ...
	nii.machine,slice_idx,img_idx,dim5_idx,dim6_idx,dim7_idx);

   return					% save_untouch_slice

%--------------------------------------------------------------------------
function save_untouch_slice_img(slice,filename,hdr,filetype,fileprefix,machine,slice_idx,img_idx,dim5_idx,dim6_idx,dim7_idx)

   if ~exist('hdr','var') | ~exist('filetype','var') | ~exist('fileprefix','var') | ~exist('machine','var')
      error('Usage: save_untouch_slice_img(slice,filename,hdr,filetype,fileprefix,machine,slice_idx,[img_idx],[dim5_idx],[dim6_idx],[dim7_idx]);');
   end

   if ~exist('slice_idx','var') | isempty(slice_idx) | hdr.dime.dim(4)<1
      slice_idx = [];
   end

   if ~exist('img_idx','var') | isempty(img_idx) | hdr.dime.dim(5)<1
      img_idx = [];
   end

   if ~exist('dim5_idx','var') | isempty(dim5_idx) | hdr.dime.dim(6)<1
      dim5_idx = [];
   end

   if ~exist('dim6_idx','var') | isempty(dim6_idx) | hdr.dime.dim(7)<1
      dim6_idx = [];
   end

   if ~exist('dim7_idx','var') | isempty(dim7_idx) | hdr.dime.dim(8)<1
      dim7_idx = [];
   end

   %  check img_idx
   %
   if ~isempty(img_idx) & ~isnumeric(img_idx)
      error('"img_idx" should be a numerical array.');
   end

   if length(unique(img_idx)) ~= length(img_idx)
      error('Duplicate image index in "img_idx"');
   end

   if ~isempty(img_idx) & (min(img_idx) < 1 | max(img_idx) > hdr.dime.dim(5))
      max_range = hdr.dime.dim(5);

      if max_range == 1
         error(['"img_idx" should be 1.']);
      else
         range = ['1 ' num2str(max_range)];
         error(['"img_idx" should be an integer within the range of [' range '].']);
      end
   end

   %  check dim5_idx
   %
   if ~isempty(dim5_idx) & ~isnumeric(dim5_idx)
      error('"dim5_idx" should be a numerical array.');
   end

   if length(unique(dim5_idx)) ~= length(dim5_idx)
      error('Duplicate index in "dim5_idx"');
   end

   if ~isempty(dim5_idx) & (min(dim5_idx) < 1 | max(dim5_idx) > hdr.dime.dim(6))
      max_range = hdr.dime.dim(6);

      if max_range == 1
         error(['"dim5_idx" should be 1.']);
      else
         range = ['1 ' num2str(max_range)];
         error(['"dim5_idx" should be an integer within the range of [' range '].']);
      end
   end

   %  check dim6_idx
   %
   if ~isempty(dim6_idx) & ~isnumeric(dim6_idx)
      error('"dim6_idx" should be a numerical array.');
   end

   if length(unique(dim6_idx)) ~= length(dim6_idx)
      error('Duplicate index in "dim6_idx"');
   end

   if ~isempty(dim6_idx) & (min(dim6_idx) < 1 | max(dim6_idx) > hdr.dime.dim(7))
      max_range = hdr.dime.dim(7);

      if max_range == 1
         error(['"dim6_idx" should be 1.']);
      else
         range = ['1 ' num2str(max_range)];
         error(['"dim6_idx" should be an integer within the range of [' range '].']);
      end
   end

   %  check dim7_idx
   %
   if ~isempty(dim7_idx) & ~isnumeric(dim7_idx)
      error('"dim7_idx" should be a numerical array.');
   end

   if length(unique(dim7_idx)) ~= length(dim7_idx)
      error('Duplicate index in "dim7_idx"');
   end

   if ~isempty(dim7_idx) & (min(dim7_idx) < 1 | max(dim7_idx) > hdr.dime.dim(8))
      max_range = hdr.dime.dim(8);

      if max_range == 1
         error(['"dim7_idx" should be 1.']);
      else
         range = ['1 ' num2str(max_range)];
         error(['"dim7_idx" should be an integer within the range of [' range '].']);
      end
   end

   %  check slice_idx
   %
   if ~isempty(slice_idx) & ~isnumeric(slice_idx)
      error('"slice_idx" should be a numerical array.');
   end

   if length(unique(slice_idx)) ~= length(slice_idx)
      error('Duplicate index in "slice_idx"');
   end

   if ~isempty(slice_idx) & (min(slice_idx) < 1 | max(slice_idx) > hdr.dime.dim(4))
      max_range = hdr.dime.dim(4);

      if max_range == 1
         error(['"slice_idx" should be 1.']);
      else
         range = ['1 ' num2str(max_range)];
         error(['"slice_idx" should be an integer within the range of [' range '].']);
      end
   end

   write_image(slice,filename,hdr,filetype,fileprefix,machine,slice_idx,img_idx,dim5_idx,dim6_idx,dim7_idx);

   return					% save_untouch_slice_img

%---------------------------------------------------------------------
function write_image(slice,fn,hdr,filetype,fileprefix,machine,slice_idx,img_idx,dim5_idx,dim6_idx,dim7_idx)

   fid = fopen(fn,'r+',machine);

   if fid < 0,
      msg = sprintf('Cannot open file %s.',fn);
      error(msg);
   end

   %  Set bitpix according to datatype
   %
   %  /*Acceptable values for datatype are*/
   %
   %     0 None                     (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN
   %     1 Binary                         (ubit1, bitpix=1) % DT_BINARY
   %     2 Unsigned char         (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8
   %     4 Signed short                  (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16
   %     8 Signed integer                (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32
   %    16 Floating point    (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32
   %    32 Complex, 2 float32      (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64
   %    64 Double precision  (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64
   %   128 uint8 RGB                 (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24
   %   256 Signed char            (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8
   %   511 Single RGB              (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96
   %   512 Unsigned short               (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16
   %   768 Unsigned integer             (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32
   %  1024 Signed long long              (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64
   %  1280 Unsigned long long           (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64
   %  1536 Long double, float128  (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128
   %  1792 Complex128, 2 float64  (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
   %  2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
   %
   switch hdr.dime.datatype
   case   2,
      hdr.dime.bitpix = 8;  precision = 'uint8';
   case   4,
      hdr.dime.bitpix = 16; precision = 'int16';
   case   8,
      hdr.dime.bitpix = 32; precision = 'int32';
   case  16,
      hdr.dime.bitpix = 32; precision = 'float32';
   case  64,
      hdr.dime.bitpix = 64; precision = 'float64';
   case 128,
      hdr.dime.bitpix = 24; precision = 'uint8';
   case 256
      hdr.dime.bitpix = 8;  precision = 'int8';
   case 511
      hdr.dime.bitpix = 96; precision = 'float32';
   case 512
      hdr.dime.bitpix = 16; precision = 'uint16';
   case 768
      hdr.dime.bitpix = 32; precision = 'uint32';
   case 1024
      hdr.dime.bitpix = 64; precision = 'int64';
   case 1280
      hdr.dime.bitpix = 64; precision = 'uint64';
   otherwise
      error('This datatype is not supported');
   end

   hdr.dime.dim(find(hdr.dime.dim < 1)) = 1;

   %  move pointer to the start of image block
   %
   switch filetype
   case {0, 1}
      fseek(fid, 0, 'bof');
   case 2
      fseek(fid, hdr.dime.vox_offset, 'bof');
   end

   if hdr.dime.datatype == 1 | isequal(hdr.dime.dim(4:8),ones(1,5)) | ...
	(isempty(img_idx) & isempty(dim5_idx) & isempty(dim6_idx) & isempty(dim7_idx) & isempty(slice_idx))

      msg = [char(10) char(10) '   "save_untouch_slice" is used to save back to the original image a' char(10)];
      msg = [msg '   portion of slices that were loaded by "load_untouch_nii". You can' char(10)];
      msg = [msg '   process those slices matrix in any way, as long as their dimension' char(10)];
      msg = [msg '   is not changed.'];
      error(msg);
   else

      d1 = hdr.dime.dim(2);
      d2 = hdr.dime.dim(3);
      d3 = hdr.dime.dim(4);
      d4 = hdr.dime.dim(5);
      d5 = hdr.dime.dim(6);
      d6 = hdr.dime.dim(7);
      d7 = hdr.dime.dim(8);

      if isempty(slice_idx)
         slice_idx = 1:d3;
      end

      if isempty(img_idx)
         img_idx = 1:d4;
      end

      if isempty(dim5_idx)
         dim5_idx = 1:d5;
      end

      if isempty(dim6_idx)
         dim6_idx = 1:d6;
      end

      if isempty(dim7_idx)
         dim7_idx = 1:d7;
      end

      %ROMAN: begin
      roman = 1;
      if(roman)

         %  compute size of one slice
         %
         img_siz = prod(hdr.dime.dim(2:3));

         %  For complex float32 or complex float64, voxel values
         %  include [real, imag]
         %
         if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792
            img_siz = img_siz * 2;
         end

         %MPH: For RGB24, voxel values include 3 separate color planes
         %
         if hdr.dime.datatype == 128 | hdr.dime.datatype == 511
            img_siz = img_siz * 3;
         end

      end; %if(roman)
      % ROMAN: end

      for i7=1:length(dim7_idx)
         for i6=1:length(dim6_idx)
            for i5=1:length(dim5_idx)
               for t=1:length(img_idx)
               for s=1:length(slice_idx)

                  %  Position is seeked in bytes. To convert dimension size
                  %  to byte storage size, hdr.dime.bitpix/8 will be
                  %  applied.
                  %
                  pos = sub2ind([d1 d2 d3 d4 d5 d6 d7], 1, 1, slice_idx(s), ...
			                    img_idx(t), dim5_idx(i5),dim6_idx(i6),dim7_idx(i7)) -1;
                  pos = pos * hdr.dime.bitpix/8;

                  % ROMAN: begin
                  if(roman)
                      % do nothing
                  else
                     img_siz = prod(hdr.dime.dim(2:3));

                     %  For complex float32 or complex float64, voxel values
                     %  include [real, imag]
                     %
                     if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792
                        img_siz = img_siz * 2;
                     end

                     %MPH: For RGB24, voxel values include 3 separate color planes
                     %
                     if hdr.dime.datatype == 128 | hdr.dime.datatype == 511
                        img_siz = img_siz * 3;
                     end
                  end; % if (roman)
                  % ROMAN: end

                  if filetype == 2
                     fseek(fid, pos + hdr.dime.vox_offset, 'bof');
                  else
                     fseek(fid, pos, 'bof');
                  end

                  %  For each frame, fwrite will write precision of value
                  %  in img_siz times
                  %
                  fwrite(fid, slice(:,:,s,t,i5,i6,i7), sprintf('*%s',precision));

               end
               end
            end
         end
      end
   end

   fclose(fid);

   return						% write_image


 function [arg, ii] = arg_get(list, what, default)
%function [arg, ii] = arg_get(list, what, default)
% extract an argument (e.g., nx or pixel_size, etc.)
% from a list (vertically concatenated strings)
% e.g., as generated by arg_pair() or strvcat()
% the *first* match is used.
% Copyright 2005, Jeff Fessler, The University of Michigan

if nargin < 1, ir_usage, end
if nargin == 1 && streq(list, 'test'), arg_get_test, return, end

list(list == '	') = ' ';	% replace tabs with spaces
what = [what ' '];
for ii=1:size(list,1)
	if streq(list(ii,:), what, length(what))
		arg = list(ii,(1+length(what)):end);
		return
	end
end
if isvar('default') && ~isempty(default)
	if isnumeric(default)
		arg = sprintf('%d', default);
	else
		arg = default;
	end
	ii = 0;
else
	fail('cannot find "%s"', what)
end

function arg_get_test
tmp = strvcat('na 9', 'nb 8', 'nxyz 7');
tmp = arg_get(tmp, 'na');
tmp = str2num(tmp);
jf_equal(tmp, 9)


function tests = test_spm_dcm_identify
% Unit Tests for test_spm_dcm_identify
%__________________________________________________________________________
% Copyright (C) 2016 Wellcome Trust Centre for Neuroimaging

% $Id: test_spm_dcm_identify.m 7479 2018-11-09 14:17:33Z peter $

tests = functiontests(localfunctions);

% -------------------------------------------------------------------------
function test_identify_dcm_fmri(testCase)

data_path = get_data_path();

DCM = load(fullfile(data_path,'DCM_fMRI.mat'));
DCM = DCM.DCM;

model = spm_dcm_identify(DCM);

testCase.assertEqual(model,'fMRI');

% -------------------------------------------------------------------------
function test_identify_dcm_fmri_csd(testCase)

data_path = get_data_path();

DCM = load(fullfile(data_path,'DCM_fMRI_CSD.mat'));
DCM = DCM.DCM;

model = spm_dcm_identify(DCM);

testCase.assertEqual(model,'fMRI_CSD');

% -------------------------------------------------------------------------
function test_identify_erp(testCase)

data_path = get_data_path();

DCM = load(fullfile(data_path,'DCM_IMG_ERP_CMC.mat'));
DCM = DCM.DCM;

model = spm_dcm_identify(DCM);

testCase.assertEqual(model,'ERP');

% -------------------------------------------------------------------------
function test_identify_csd(testCase)

data_path = get_data_path();

DCM = load(fullfile(data_path,'DCM_LFP_CSD_CMC.mat'));
DCM = DCM.DCM;

model = spm_dcm_identify(DCM);

testCase.assertEqual(model,'CSD');

% -------------------------------------------------------------------------
function test_identify_ind(testCase)

data_path = get_data_path();

DCM = load(fullfile(data_path,'DCM_IND.mat'));
DCM = DCM.DCM;

model = spm_dcm_identify(DCM);

testCase.assertEqual(model,'IND');

% -------------------------------------------------------------------------
function data_path = get_data_path()

data_path = fullfile( spm('Dir'), 'tests', ...
    'data', 'test_spm_dcm_identify');