function varargout = guidefunc(type, varargin)
%GUIDEFUNC Support function for Guide

%   Copyright 1984-2000 The MathWorks, Inc.
%   $Revision: 1.35 $

try

  switch type,

    case 'newFigure'
      layout_ed = varargin{1};
      fig = newGuideFig(layout_ed);
      set(fig,'tag',nextTag(fig));
      options = guideopts(fig);
      if options.syscolorfig
	set(fig,...
	    'color', get(0, 'defaultuicontrolbackgroundcolor'));
      end
      varargout{1} = fig;
      varargout{2} = requestJavaAdapter(fig);
      varargout{3} = localGetPixelPos(fig);

    case 'newUicontrol'
      fig = varargin{1};
      h = uicontrol('parent', fig, ...
          'position', varargin{2}, ...
          'style', varargin{3}, ...
          'string', varargin{4});
      set(h,'units','character','tag',nextTag(h));
      options = guideopts(fig);
      if strcmp(options.resize, 'simple')
	set(h, 'units', 'normalized')
      end
      if options.mfile & options.callbacks
	guidemfile('chooseAutoCallbacks',h);
      end

      varargout{1} = h;
      varargout{2} = requestJavaAdapter(h);
      varargin{5}.updateProxy(varargout{2});

    case 'newAxes'
     fig = varargin{1};
     h = axes('parent', fig, ...
          'units', 'pixels', ...
          'position', varargin{2});
      set(h, 'units','character','tag',nextTag(h));

      options = guideopts(fig);
      if strcmp(options.resize, 'simple')
	set(h, 'units', 'normalized')
      end

      varargout{1} = h;
      varargout{2} = requestJavaAdapter(h);
      varargin{3}.updateProxy(varargout{2});
    
    case 'readFigure'
     layout_ed = varargin{1};
     filename = varargin{2};
     fig = newGuideFig(layout_ed, filename);
      varargout{1} = fig;
      varargout{2} = requestJavaAdapter(fig);
      varargout{3} = localGetPixelPos(fig);
      [varargout{4:6}] = localScanChildren(get(fig,'children'), [], varargout{3}(4));
      
    case 'duplicate'
     originals = varargin{1};
     parents = varargin{2};
     fig = findParentFigure(parents(1));
     dups = copyobj(originals, parents);
     options = guideopts(fig);
      for i=1:length(dups)
	set(dups(i), 'tag', nextTag(dups(i)));
	if options.mfile & options.callbacks
	  guidemfile('chooseAutoCallbacks',dups(i));
	end
      end
      figPos = localGetPixelPos(varargin{2});
      offset = [varargin{3}(1) -varargin{3}(2) 0 0];
      [varargout{1:3}] = localScanChildren(dups, offset, figPos(4));
      markDirty(fig);
      
    case 'copy'
      copyContents = varargin{1};
      copyBuffer = varargin{2};
      if isempty(copyBuffer)
        copyBuffer = newGuideFig;
      else
        delete(get(copyBuffer,'children'));
      end
      newList = copyobj(copyContents, copyBuffer);
      varargout{1} = newList;
      varargout{2} = copyBuffer;
      
    case 'activateFigure'
     fig = varargin{1};
     options = guideopts(fig);
     
      filename = get(fig,'filename')
      is_temp_file = 0;
      already_saved = 0;
      if isempty(filename) % figure has not yet been saved:
	if options.mfile % if we're in M-file mode, force a save now:	  
	  if strcmp(okToSave,'no')
	    return
	  end
	  guidefunc('save', fig);
	  already_saved = 1;
	  filename = get(fig, 'filename');
	  if isempty(filename) % treat this as a cancel:
	    return;
	  end
	else % otherwise, just generate a temp .fig file
	  filename = [tempname '.fig'];
	  is_temp_file = 1;
	end
      end
	
      if ~is_temp_file & ~already_saved
	layout_ed = getappdata(fig, 'GUIDELayoutEditor');
	if layout_ed.getDirty | guidemfile('isMFileDirty',filename)
	  if strcmp(okToSave, 'no')
	    return
	  end
	end
      end
      saveGuideFig(fig, filename);
      
      [path, fcn, ext] = fileparts(filename);

      options.active_h = unique(options.active_h(ishandle(options.active_h)));
      if options.singleton & options.mfile
	% if we're in singleton mode, make sure to delete all
	% other copies so that the MFile actually creates a new
	% copy instead of raising the last one:
	delete(options.active_h);
	options.active_h = [];
      end
      % if we're in MFile mode, and we've got the MFile, then
      % activate by calling the MFile (for highest fidelity)
      if ~is_temp_file & options.mfile & strcmpi(which(fcn), fullfile(path, [fcn '.m']))
	% keep track of the new figure handle
	figs_before = allchild(0);
	try
	  feval(fcn);
	catch
	  errordlg(['Error while attempting to activate figure.',10,lasterr],...
		   'GUIDE');
	end
	% capture the new handle (if any), by comparing the root's
        % list of children before and after calling the MFile.
        % Don't assume the MFile returns the figure handle, because
        % users might change that!
	options.active_h = [options.active_h setdiff(allchild(0), figs_before)];
      else
	new_fig = hgload(filename);
	options.active_h(end + 1) = new_fig;
	% If we're in "companion mfile" mode, and we activate
        % before having done a SAVE, many of our callbacks will
        % have strings that error out.  Just clear out those
        % callbacks in the "activated" figure:
	% PS - I don't think we need this anymore, as we now
	% force a save upon the first activate.
	if is_temp_file & options.mfile
	  guidemfile('loseAutoCallbacks', new_fig);
	end
      end

      if is_temp_file
	delete(filename);
      end
      
      guideopts(fig, options);
      
    case 'snapshotFigure'
      fig = snapshotFig(varargin{2}, varargin{1});
      varargout{1} = fig;
      varargout{2} = requestJavaAdapter(fig);
      varargout{3} = get(fig,'position');
      [varargout{4:6}] = localScanChildren(get(fig,'children'), [], varargout{3}(4));
      
   case 'save'
    fig = varargin{1};
    if nargin > 2
      filename = varargin{2};
    else
      filename = get(fig, 'filename');
    end
    if ~isempty(filename)
      layout_ed = getappdata(fig, 'GUIDELayoutEditor');
      saveGuideFig(fig, filename);
      layout_ed.writeCompleted(java.lang.String(filename));
    else
      guidefunc('saveAs',fig);
    end
    
   case 'saveAs'
    fig = varargin{1};
    default_name = get(fig,'filename');
    if isempty(default_name)
      layout_ed = getappdata(fig, 'GUIDELayoutEditor');
      default_name = [char(layout_ed.getRuntimeName) '.fig'];
    end
    options = guideopts(fig);
    
    % Put up a Save-as dialog box, and check the return result.
    % If the user picks a bad name, or chooses a write-protected 
    % file or directory, put up an error message and then redisplay
    % the save-as dialog, until the user gets it right, or Cancels.
    while 1
      [filename, pathname] = uiputfile(default_name,'Save Figure As:');
      %{'*.fig', 'FIG-Files (*.fig)'}, ..
     
      if isequal(filename, 0) | isequal(pathname, 0) %CANCEL
	return;
      end
      [p, f, e] = fileparts([pathname filename]);
      if isempty(e)
	e = '.fig'; % ALLOW filename to be typed w/o .fig extension
      end
      ErrMsg = '';
      if ~strcmp(e, '.fig') % Don't allow any other extension
	ErrMsg = 'You must choose a FIG-file to save';
      elseif ~isvarname(f)
	ErrMsg = ['You must choose a legal MATLAB function name, ' ...
		  'which is a character string of letters, digits ',...
		  'and underscores, with length <= 31 and the first '...
		  'character a letter'];
      else
	figfile = fullfile(p, [f e]);
	fid = fopen(figfile,'a'); %Make sure we have write
                                  %permission to the .fig file
	if fid == -1
	  ErrMsg = ['Write permission denied for .fig file: ',10,...
		    figfile,10,...
		    'Make sure the directory and file are not read-only.'];
	else
	  fclose(fid);
	  if options.mfile
	    mfile = fullfile(p, [f '.m']);
	    existedBefore = exist(mfile);

	    fid = fopen(mfile,'a'); % make sure we have write
                                    % permission for the mfile.
                                    % Careful - don't leave an
                                    % empty one behind...
	    if fid == -1
	      ErrMsg = ['Write permission denied for application M-file:',10,...
			mfile,10,...
			'Make sure the directory and file are not read-only.'];
	    else
	      fclose(fid);
	      if ~existedBefore
		delete(mfile);
	      else
		wish=questdlg([mfile,...
			       ' already exists.  Do you wish' ...
			       ' to replace it or append to it?'],...
			      'Save Figure As', ...
			      'Replace','Append','Cancel','Replace');
		switch wish
		 case 'Cancel'
		  return;
		 case 'Replace'
		  delete(mfile);
		end
	      end
	    end
	  end
	end
      end

      % If there was a file or permission error, display the error,
      % then loop around again to reopen the file selection dialog:
      if ~isempty(ErrMsg)
	uiwait(errordlg(ErrMsg, 'GUIDE'));
	continue;
      end
      % if we got here, we have a good filename, and write
      % permission on the fig file, and if necessary, the mfile
      guidefunc('save',fig,figfile);
      break; 
             
    end % end while 1
    
      
    case 'delete'
      delete(varargin{1});
      
    case 'move'
      localSetPixelPos(varargin{1}, varargin{2});
      % force a completion call
      varargout{1} = 0;
      
    case 'moveToFront'
      uistack(varargin{1},'top');
      
    case 'moveToBack'
      uistack(varargin{1},'bottom');
      
    case 'moveForward'
      uistack(varargin{1},'up');
      
    case 'moveBackward'
      uistack(varargin{1},'down');
      
    case 'resizeFigure'
      fig = varargin{1};
      size = varargin{2};
      saveUnits = get(fig, 'units');
      set(fig, 'units', 'pixels');
      pos = get(fig, 'position');
      y = pos(2) + pos(4) - size(2);
      set(fig, 'position', [pos(1) y size]);
      set(fig, 'units', saveUnits);
      % force a completion call
      varargout{1} = 0;

   case 'openFigure'
    [filename, pathname] = uigetfile( ...
	{'*.fig', 'FIG-Files (*.fig)'; ...
	 '*.*',   'All Files (*.*)'}, ...
	'Pick a file')

    if isequal(filename, 0) | isequal(pathname, 0) %CANCEL
	return;
    end
    
    [p, f, e] = fileparts([pathname filename]);
    if strcmp(e, '.fig')
      guide([pathname filename]);
    else
      uiopen([pathname filename], 'direct');
    end
    
    %uiwait(msgbox('please add code for opening here', 'modal'));
      
   case 'helpUsingLayout'
    helpview([docroot '/mapfiles/creating_guis.map'], 'layout_editor')
    
   case 'helpCreatingGUIs'
    helpview([docroot '/mapfiles/creating_guis.map'], 'creating_guis')
    
   case 'applicationOptions'
    fig = varargin{1};
    guideopts(fig, 'edit');
    
   case 'editCallback'
    obj = varargin{1};
    whichCb = varargin{2};
    fig = findParentFigure(obj);
    options = guideopts(fig);
    if options.mfile & options.callbacks 
      % write out this callback to the MFile, and scroll to it:
      guidemfile('setAutoCallback',obj, whichCb);
      guidefunc('save',findParentFigure(obj));
      guidemfile('scrollToCBSubfunction', obj, whichCb);
    else
      % If not in mfile mode, go to this callback in the inspector,
      % and highlight it:
      com.mathworks.ide.inspector.Inspector.activateInspector;
      com.mathworks.ide.inspector.Inspector.getInspector.selectProperty(whichCb);
    end
 end

catch
  if ~isempty(lasterr)
    errordlg(['Unhandled internal error in guidefunc.',10,lasterr], ...
	     'GUIDE');
  else
    %errordlg('Unexpected CATCH in guidefunc with empty LASTERR');
  end
end
 

%************************************************
function fig = findParentFigure(h)
% utility for searching up the instance hierarchy for the figure ancestor
while ~isempty(h) & ~strcmp(get(h,'type'),'figure')
    h = get(h,'parent');
end
fig = h;
%------------- end findParentFigure -------------

function tag = nextTag(obj)
% utility for returning the next unique tag for any object
    fig = findParentFigure(obj);
    if isempty(fig)
      tag = '';
    else
      options = guideopts(fig);
      objType = get(obj,'type');
      if(strcmp(objType,'uicontrol'))
        objType = get(obj,'style');
      end
      if ~isfield(options.taginfo,objType)
        options.taginfo = setfield(options.taginfo,objType,1);
      end
      num = getfield(options.taginfo,objType);
      tag = [objType, num2str(num)];
      options.taginfo = setfield(options.taginfo,objType,num+1);
      guideopts(fig,options);
    end

function [hndl,adpt,prox] = localScanChildren(objects, offset, parentHeight)
  uiKids = findobj(objects,'type','uicontrol');
  axKids = findobj(objects,'type','axes');
  kids = [uiKids;axKids];
  limit = length(kids);
  hndl = zeros(limit,1);
  adpt = cell(limit,1);
  prox = cell(limit,1);
  for i = 1:limit
    obj = kids(i);
    typeID = localGetTypeID(obj);
    if (typeID == 10)
      str = '';
      contents = get(obj,'children');
      if ~isempty(contents)
        % this is where I delete axes children
        delete(contents);
      end
    else
      str = localGetString(obj);
    end
    pos = localGetPixelPos(obj);
    if ~isempty(offset)
      pos = pos + offset;
      localSetPixelPos(obj, pos);
    end
    hndl(i) = obj;
    adpt{i} = requestJavaAdapter(obj);
    prox{i} = com.mathworks.ide.layout.GObjectProxy(typeID,str,adpt{i},parentHeight);
  end

%************************************************
function typeID = localGetTypeID(obj)
  typeID = -1;
  typeStr = get(obj,'type');
  if strcmp(typeStr, 'axes') ~= 0
    typeID = 10;
  elseif strcmp(typeStr,'uicontrol') ~= 0
    styleStr = get(obj,'style');
    if strcmp(styleStr,'pushbutton') ~= 0
      typeID = 0;
    elseif strcmp(styleStr,'slider') ~= 0
      typeID = 1;
    elseif strcmp(styleStr,'radiobutton') ~= 0
      typeID = 2;
    elseif strcmp(styleStr,'checkbox') ~= 0
      typeID = 3;
    elseif strcmp(styleStr,'edit') ~= 0
      typeID = 4;
    elseif strcmp(styleStr,'text') ~= 0
      typeID = 5;
    elseif strcmp(styleStr,'frame') ~= 0
      typeID = 6;
    elseif strcmp(styleStr,'popupmenu') ~= 0
      typeID = 7;
    elseif strcmp(styleStr,'listbox') ~= 0
      typeID = 8;
    elseif strcmp(styleStr,'togglebutton') ~= 0
      typeID = 9;
    end
  end

%************************************************
function pixelPos = localGetPixelPos(obj)
  saveUnits = get(obj, 'units');
  set(obj, 'units', 'pixels');
  pixelPos = get(obj, 'position');
  set(obj, 'units', saveUnits);

%************************************************
function localSetPixelPos(obj, pos)
  saveUnits = get(obj, 'units');
  set(obj, 'units', 'pixels');
  set(obj, 'position', pos);
  set(obj, 'units', saveUnits);

%************************************************
function str = localGetString(obj)
  str = get(obj, 'string');
  if ~iscell(str) & min(size(str)) > 1
    str = cellstr(str);
  end

%************************************************
% takes an existing figure and 'snapshots' it
% into a GUIDE internal figure
function newFig = snapshotFig(fig, layout_ed)
  filename = [tempname '.fig'];
  hgsave(fig, filename);
  newFig = newGuideFig(layout_ed, filename);
  % If we are editing an existing open figure, forget which file it
  % may have come from - we don't want to automatically overwrite
  % that file when we do Save.  This will make the figure do a
  % SaveAs the first time it is saved, and will protect the
  % original fig file.
  set(newFig, 'filename', '');
  delete(filename);

%************************************************
% Saves an internal GUIDE figure to a fig file,
% making sure to remove the internal GUIDE info
% first.
function saveGuideFig(fig, filename)

% remove this from appdata for two reasons:
% 1) we don't want it saved/reloaded with the figure
% 2) there's a bug in saving with java objects...
layout_ed = getappdata(fig, 'GUIDELayoutEditor');
if isappdata(fig, 'GUIDELayoutEditor')
  rmappdata(fig, 'GUIDELayoutEditor');
end
p = findprop(handle(fig), '__GUIDEFigure');
delete(p);
[path, funcname, ext] = fileparts(filename);
options = guideopts(fig);
if options.mfile
  guidemfile('updateFile', fig, filename);
end
%uiwait(msgbox(['saving figure to file: ' filename]))
hgsave(fig, filename);
set(fig, 'filename', filename)
p = schema.prop(fig, '__GUIDEFigure', 'double');
if ~isempty(layout_ed)
  setappdata(fig, 'GUIDELayoutEditor', layout_ed)
end
layout_ed.setDirty(0);

%************************************************
% Loads or creates a figure, initializing it
% for internal use by GUIDE. If a filename is
% specified, it loads the figure from that
% file, otherwise it creates a new figure.
function fig = newGuideFig(layout_ed, filename)

if nargin == 2 & ~isempty(filename)
  [p,f,e] = fileparts(filename);
  if isempty(e)
    e = '.fig';
  end
  filename = fullfile(p, [f, e]);
  
  overrides.Visible = 'off';
  overrides.IntegerHandle = 'off';
  [fig, old_vals] = hgload(filename, overrides);
  if isfield(old_vals{1}, 'Visible')
    vis = old_vals{1}.Visible;
  else
    vis = 'on';
  end
  if isfield(old_vals{1}, 'IntegerHandle')
    intHandle = old_vals{1}.IntegerHandle;
  else
    intHandle = 'on';
  end

  figFile = get(fig,'filename');
  [path,name,ext]=fileparts(figFile);
  mFile = fullfile(path, [name '.m']);

  if ~exist(mFile)
    options = guideopts(fig);
    options.mfile = 0;
    guideopts(fig, options);
  end
    
else % create blank figure, don't load from FIG-file
  intHandle = 'off';
  vis = 'on';
  
  fig = figure('visible','off',...
	       'menubar','none',...
	       'numbertitle','off',...
	       'handlevisibility','off',...
	       'integerhandle', 'off',...
	       'name','Untitled',...
	       'units','character',...
               'resize','off');
end

if nargin >= 1
  setappdata(fig, 'GUIDELayoutEditor', layout_ed);
end

p = schema.prop(fig, '__GUIDEFigure', 'double');
set(fig, 'visible', vis);
set(fig, 'integerhandle', intHandle);

if isappdata(0, 'MathWorks_GUIDE_testmode')
  options = guideopts(fig);
  options.mfile = 0;
  guideopts(fig, options);
end

function ans = okToSave
[ans,shown]=uigetpref('MathWorks_GUIDE','savebeforeactivating','GUIDE',...
		      ['Activating will save changes to your ',...
		    'figure and M-file. Do you wish to continue?'],...
		      {'yes','no';'Yes','No'},...
		      'DefaultButton','Yes',...
		      'CheckboxString','Don''t tell me again.');
if strcmp(ans, 'no') ...
      & shown ...
      & isequal(getpref('MathWorks_GUIDE', 'savebeforeactivating'),'no')
  
  % if user checked the "don't ask again box", store a preference
  % of 'yes' even if he clicked the no button for this time.
  setpref('MathWorks_GUIDE','savebeforeactivating', 'yes');

end


function markDirty(fig)

layout_ed = getappdata(fig, 'GUIDELayoutEditor')
layout_ed.setDirty(1);
