Code covered by the BSD License  

Highlights from
Convert FIG to MATLAB code

from Convert FIG to MATLAB code by Thomas Montagnon
Generate programmatic GUI MATLAB File from a FIG-File

fig2m(guiName,outputDir,syscolorfig,cb_gen)
function varargout = fig2m(guiName,outputDir,syscolorfig,cb_gen)
% FIG2M - Generate programmatic GUI M-File from a FIG-File
%
% Version : 1.0
% Created : 10/05/2006
% Modified: 14/04/2010
% Author  : Thomas Montagnon (The MathWorks France)
%
% >> outputFile = fig2m(guiName,outputDir,syscolorfig,cb_gen);
%
%    guiName     -> Name of the Fig-File (absolute or relative path)
%    outputDir   -> Directory where the generated M-File will be saved
%    syscolorfig -> Use system default background color (true or false)
%    cb_gen      -> Generate callbacks (true or false)
%    outputFile  -> Name of the generated M-File
%
% >> fig2m
%
%    If you call the function with no input arguments it will ask you for the
%    parameters.


% INPUT ARGUMENTS

if nargin < 4
  % Generate callbacks
  answer = questdlg('Do you want to generate the callbacks?','Callbacks','Yes','No','Yes');
  if strcmp(answer,'Yes')
    cb_gen = true;
  else
    cb_gen = false;
  end
end

if nargin < 3
  % Use system default background color
  answer = questdlg('Do you want to use the system default background color?','Background color','Yes','No','Yes');
  if strcmp(answer,'Yes')
    syscolorfig = true;
  else
    syscolorfig = false;
  end
end

if nargin == 1
  
  % Check if guiName is a directory or a file
  if exist(guiName,'dir')
    [guiName,guiPath] = uigetfile(fullfile(guiName,'*.fig'),'Choose a FIG-File');
    if isequal(guiName,0)
      return
    end
    guiName = fullfile(guiPath,guiName);
  end
  
  % Output directory
  outputDir = uigetdir(guiPath,'Choose the output directory');
  if isequal(outputDir,0)
    return
  end
  
end

if nargin == 0
  
  % Fig-File
  [guiName,guiPath] = uigetfile('*.fig','Choose a FIG-File');
  if isequal(guiName,0)
    return
  end
  guiName = fullfile(guiPath,guiName);
  
  % Output directory
  outputDir = uigetdir(guiPath,'Choose the output directory');
  if isequal(outputDir,0)
    return
  end
  
end



if ~exist(guiName,'file')
  error('Bad input argument');
end

% Get info about the FIG-File
[guiPath,guiName,guiExt] = fileparts(guiName);

% Stop the execution of the function if the FIG-File doesn't exist or is invalid
if ~strcmpi(guiExt,'.fig')
  uiwait(errordlg('Invalid GUI file','Error'));
  varargout{1} = '';
  return
end
if ~exist(fullfile(guiPath,[guiName,guiExt]),'file')
  uiwait(errordlg('GUI file not exists','Error'));
  varargout{1} = '';
  return
end

% Output file name
outputFile = [guiName '_build.m'];

% Name of the output file
outFile = fullfile(outputDir,outputFile);

% Graphic objects categories
Categories = {...
  'FIGURE',...
  'CONTEXT MENUS',...
  'MENU ITEMS',...
  'PANELS',...
  'AXES',...
  'LINES',...
  'SURFACES',...
  'STATIC TEXTS',...
  'PUSHBUTTONS',...
  'TOGGLE BUTTONS',...
  'RADIO BUTTONS',...
  'CHECKBOXES',...
  'EDIT TEXTS',...
  'LISTBOXES',...
  'POPUP MENU',...
  'SLIDERS',...
  'UITABLE',...
  'TOOLBAR', ...
  'PUSH TOOLS', ...
  'TOGGLE TOOLS'};

% Default Tags
DefTags = {...
  'figure',...
  'menu',...
  'menuitem',...
  'panel',...
  'axes',...
  'line',...
  'surf',...
  'text',...
  'pushbutton',...
  'togglebutton',...
  'radiobutton',...
  'checkbox',...
  'edit',...
  'listbox',...
  'popupmenu',...
  'slider',...
  'uitable',...
  'uitoolbar', ...
  'uipushtool', ...
  'uitoggletool'};

% Callbacks names
cb_names = { ...
  'Callback', ...
  'ButtonDownFcn', ...
  'CreateFcn', ...
  'DeleteFcn', ...
  'KeyPressFcn', ...
  'KeyReleaseFcn', ...
  'ResizeFcn', ...
  'WindowButtonDownFcn', ...
  'WindowButtonMotionFcn', ...
  'WindowButtonUpFcn', ...
  'WindowScrollWheelFcn', ...
  'SelectionChangeFcn', ...
  'ClickedCallback', ...
  'OffCallback', ...
  'OnCallback', ...
  'CellEditCallback', ...
  'CellSelectionCallback'};

% Default properties values
dprop = default_prop_values();

% Properties for each style of objects
prop = control_properties();

idList = fieldnames(prop);

% Ouput file header
header = sprintf([...
  'function fig_hdl = %s\n' ...
  '%% %s\n' ...
  '%%-------------------------------------------------------------------------------\n' ...
  '%% File name   : %-30s\n' ...
  '%% Generated on: %-30s\n' ...
  '%% Description :\n' ...
  '%%-------------------------------------------------------------------------------\n' ...
  '\n\n'], ...
  outputFile(1:end-2),...
  upper(outputFile(1:end-2)),...
  outputFile,...
  datestr(now));

try

  % Open the GUI
  cdir = pwd;
  cd(guiPath);
  figFcn = str2func(guiName);
  figHdl = figFcn();
  cd(cdir);
%   figHdl = openfig(fullfile(guiPath,[guiName,'.fig']));

pause(.1);

  % Set Window style & CloseRequestFcn for GUI in order to hide the figure
  set(figHdl,'WindowStyle','normal','CloseRequestFcn','closereq','visible','off');
  
  pause(.1);

  % List all the graphic object by category
  list.Fg = figHdl;
  list.Cm = sort(findobj(figHdl,'Type', 'uicontextmenu'));
  list.Mb = sort(findobj(figHdl,'Type', 'uimenu'));
  list.Pa = sort(findobj(figHdl,'Type', 'uipanel'));
  list.Ax = sort(findobj(figHdl,'Type', 'axes'));
  list.Li = sort(findobj(figHdl,'Type', 'line'));
  list.Sf = sort(findobj(figHdl,'Type', 'surface'));
  list.Ta = sort(findobj(figHdl,'Type', 'uitable'));
  list.To = sort(findobj(figHdl,'Type' ,'uitoolbar'));
  list.Pt = sort(findobj(figHdl,'Type' ,'uipushtool'));
  list.Tt = sort(findobj(figHdl,'Type' ,'uitoggletool'));
  list.St = sort(findobj(figHdl,'Style','text'));
  list.Pb = sort(findobj(figHdl,'Style','pushbutton'));
  list.Tb = sort(findobj(figHdl,'Style','togglebutton'));
  list.Rb = sort(findobj(figHdl,'Style','radiobutton'));
  list.Cb = sort(findobj(figHdl,'Style','checkbox'));
  list.Ed = sort(findobj(figHdl,'Style','edit'));
  list.Lb = sort(findobj(figHdl,'Style','listbox'));
  list.Pu = sort(findobj(figHdl,'Style','popupmenu'));
  list.Sl = sort(findobj(figHdl,'Style','slider'));
  
  % Init callback list
  if cb_gen
    cb_list = {};
  end

  % Start writing the output file
  str = sprintf('%s',header);
  
  % Add command to init the handles structure
  str = sprintf('%s%% Initialize handles structure\nhandles = struct();\n\n',str);
  
  % Creat all controls
  str = sprintf('%s%% Create all UI controls\nbuild_gui();\n\n',str);
  
  % Add command line to assign output variable
  str = sprintf('%s%% Assign function output\nfig_hdl = handles.%s;\n\n',...
    str,get(list.Fg,'Tag'));
  
  % Create a nested function to build all uicontrols
  str = sprintf('%s%%%% ---------------------------------------------------------------------------\n',str);
  str = sprintf('%s\tfunction build_gui()\n%% Creation of all uicontrols\n\n',str);

  % Write the generation code for all the objects, grouped by category
  for indCat=1:length(idList)

    % Handles vector and properties list for the current category
    hdlsTemp = list.(idList{indCat});
    propTemp = prop.(idList{indCat});

    % Object creation function depending on the category
    switch idList{indCat}
      case 'Fg'
        ctrlFcn = 'figure';
      case 'Pa'
        ctrlFcn = 'uipanel';
      case 'Ta'
        ctrlFcn = 'uitable';
      case 'Mb'
        ctrlFcn = 'uimenu';
      case 'Cm'
        ctrlFcn = 'uicontextmenu';
      case 'Ax'
        ctrlFcn = 'axes';
      case 'Li'
        ctrlFcn = 'line';
      case 'Sf'
        ctrlFcn = 'surf';
      case 'To'
        ctrlFcn = 'uitoolbar';
      case 'Pt'
        ctrlFcn = 'uipushtool';
      case 'Tt'
        ctrlFcn = 'uitoggletool';
      otherwise
        ctrlFcn = 'uicontrol';
    end

    % If there are objects from the current category then write code
    if ~isempty(hdlsTemp)

      % Category name
      str = sprintf('%s\t\t%% --- %s -------------------------------------\n',str,Categories{indCat});

      % Init index for empty tags
      idxTag = 1;
      
      % Browse all the object belonging to the current category
      for indObj=1:length(hdlsTemp)

        % Get property values for the current object
        listTemp = get(hdlsTemp(indObj));
        
        % If tag is empty then create one
        if isempty(listTemp.Tag)
          listTemp.Tag = sprintf('%s%u',DefTags{indCat},idxTag);
          set(hdlsTemp(indObj),'Tag',listTemp.Tag);
          idxTag = idxTag + 1;
        end

        % Special treatment for UIButtongroup (UIButtongroup are UIPanel with
        % the SelectedObject property): Change creation function name
        if strcmp(idList{indCat},'Pa')
          if isfield(listTemp,'SelectedObject')
            ctrlFcn = 'uibuttongroup';
          end
        end

        % Start object creation code
        % (store all the objects handles in a handles structure)
        str = sprintf('%s\t\thandles.%s = %s( ...\n',str,listTemp.Tag,ctrlFcn);

        % Browse the object properties
        for indProp=1:length(propTemp)

          % For Parent & UIContextMenu properties, value is an object handle
          if strcmp(propTemp{indProp},'Parent') || strcmp(propTemp{indProp},'UIContextMenu')
            if ~isempty(listTemp.(propTemp{indProp}))
              propVal = sprintf('handles.%s',get(listTemp.(propTemp{indProp}),'Tag'));
            else
              propVal = [];
            end
          else
            propVal = listTemp.(propTemp{indProp});
          end
          
          if ~isfield(dprop,propTemp{indProp}) || ~isequal(propVal,dprop.(propTemp{indProp}))

            % Create Property/Value string according to the class of the property
            % value
            switch class(listTemp.(propTemp{indProp}))

              case 'char'
                s = format_char();

              case {'double','single','uint8'}
                s = format_numeric();
                
              case 'cell'
                s = format_cell();
                
              case 'logical'
                s = format_logical();

            end % end of switch

            % Write the code line 'Property','Value',...
            str = sprintf('%s\t\t\t''%s'', %s, ...\n',str,propTemp{indProp},s);

          end % end isequal

        end % Next property
        
        % Callbacks
        if cb_gen
          
          % Extract all property names
          l = fieldnames(listTemp);
          
          % Find defined callback properties
          [iprop,icb] = find(strcmp(repmat(l,1,length(cb_names)),repmat(cb_names,length(l),1))); %#ok<ASGLU>
          
          for indCb=1:length(icb)
            if ~isempty(listTemp.(cb_names{icb(indCb)}))
              cb_list{end+1} = [listTemp.Tag '_' cb_names{icb(indCb)}]; %#ok<AGROW>
              str = sprintf('%s\t\t\t''%s'', %s, ...\n',str,cb_names{icb(indCb)},['@' cb_list{end}]);
            end
          end
          
        end

        % Suppress the 5 last characters (, ...) and finish the creation command
        str(end-5:end) = '';
        str = sprintf('%s);\n\n',str);

      end % Next object

    end % End if ~isempty(hdlsTemp)

  end % Next object category
  
  % Close the build_gui nested function
  str = sprintf('%s\n\tend\n\n',str);
  
  % Add callback functions
  if cb_gen
    for indCb=1:length(cb_list)
      str = sprintf('%s%%%% ---------------------------------------------------------------------------\n',str);
      str = sprintf('%s\tfunction %s(hObject,evendata) %%#ok<INUSD>\n\n',str,cb_list{indCb});
      str = sprintf('%s\tend\n\n',str);
    end
  end
  
  % Close main function
  str = sprintf('%send\n',str);

  % Close the figure
  close(figHdl);

  % Write the output file
  fid = fopen(outFile,'w');
  fprintf(fid,'%s',str);
  fclose(fid);
  
  % Open the generated M-File in the editor
  edit(outFile);

  % Return the name of the output file
  varargout{1} = outFile;

catch ME
  varargout{1} = outFile;
  try %#ok<TRYNC>
    close(figHdl);
  end
  disp(listTemp.Tag);
  disp(ME.message);
end


  function s = format_cell()
    
    % Cell arrays (Create a single string with each cell separated by
    % a | character)
    
    if strcmpi(propTemp{indProp},'ColumnFormat') && all(cellfun(@isempty,propVal))
      s = ['{' repmat('''char'' ',size(propVal)) '}'];
      
    elseif strcmpi(propTemp{indProp},'ColumnFormat')
      s = sprintf('''%s'',',propVal{:});
      s = ['{' strrep(s(1:end-1),'''''','[]') '}']; % Handles the case of automatic column format
      
    elseif strcmpi(propTemp{indProp},'ColumnWidth')
      s = propVal;
      s(cellfun(@isstr,s))     = cellfun(@(string) ['''' string ''''],s(cellfun(@isstr,s)),'UniformOutput',false);
      s(cellfun(@isnumeric,s)) = cellfun(@num2str,s(cellfun(@isnumeric,s)),'UniformOutput',false);
      s = sprintf('%s,',s{:});
      s = ['{' s(1:end-1) '}'];
      
    elseif strcmpi(propTemp{indProp},'Data')
      ft = struct('char','''%s'',','logical','logical(%d),','double','%f,');
      classes = cellfun(@class,propVal(1,:),'UniformOutput',false);
      s = cellfun(@(s) ft.(s),classes,'UniformOutput',false);
      fmt = [s{:}];
      fmt = [fmt(1:end-1) ';'];
      propVal = propVal';
      s = sprintf(fmt,propVal{:});
      s = strrep(s,'logical(0)','false');
      s = strrep(s,'logical(1)','true');
      s = ['{' s(1:end-1) '}'];
      
    else
      s = sprintf('''%s'',',propVal{:});
      s = ['{' s(1:end-1) '}'];
    end
    
  end

  function s = format_numeric()
    % Numeric (Convert numerical value into string)
    
    
    if syscolorfig && strcmpi(idList{indCat},'Fg') && strcmpi(propTemp{indProp},'Color')
      % When using the system default background colors then override the
      % property value
      s = 'get(0,''DefaultUicontrolBackgroundColor'')';
      
    elseif any(strcmpi(propTemp{indProp},{'BackgroundColor','ForegroundColor','Color'}))
      % Limit to 3 digits for all colors vectors/matrices
      s = mat2str(propVal,3);
      
    elseif any(strcmpi(propTemp{indProp},{'Parent','UIContextMenu'}))
      % Simply output the handles.<tag> characters string when the property is
      % either Parent or UIContextMenu
      s = sprintf('%s',propVal);
      
    else
      if length(size(propVal)) > 2
        matLin = propVal(:);
        s = sprintf(',%u',size(propVal));
        s = sprintf('reshape(%s%s)',mat2str(matLin),s);
      else
        s = mat2str(propVal);
      end
      
    end
    
  end

  function s = format_char()
    % Characters
    
    if size(propVal,1) > 1
      % For character arrays that have more than 1 line
      s = 'sprintf(''';
      for j=1:size(propVal,1)
        s = sprintf('%s\t\t%s\\n',s,strrep(propVal(j,:),'''',''''''));
      end
      s = [s ''')'];
      
    elseif ~isempty(findstr(propVal,char(13)))
      % For character arrays that contain new line character
      s = sprintf('sprintf(''%s'')',strrep(strrep(strrep(propVal,char(13),'\n'),char(10),''),'''',''''''));
      
    else
      % For character arrays that have a single line and no new line
      s = sprintf('''%s''',strrep(propVal,'''',''''''));
      
    end
    
  end

  function s = format_logical()
    % Format logical property values
    
    trueFalse = {'false,','true,'};
    s = trueFalse(propVal+1);
    s = [s{:}];
    s = ['[' s(1:end-1) ']'];
    
  end

end


%-------------------------------------------------------------------------------
function cprop = control_properties()

% Common objects properties
prop.Def   = {'Parent','Tag','UserData','Visible'};
prop.Font  = {'FontAngle','FontName','FontSize','FontUnits','FontWeight'};
prop.Color = {'ForegroundColor','BackgroundColor'};
prop.Pos   = {'Units','Position'};
prop.Str   = {'String','TooltipString'};

% Properties for each style of objects
cprop.Fg = [{'Tag'}, prop.Pos, {'Name','MenuBar','NumberTitle','Color','Resize','UIContextMenu'}];
cprop.Cm = [prop.Def];
cprop.Mb = [prop.Def, {'Label','Checked','Enable','ForegroundColor'}];
cprop.Pa = [prop.Def, prop.Pos, prop.Font, prop.Color, {'Title','TitlePosition','BorderType','BorderWidth','HighlightColor','ShadowColor','UIContextMenu'}];
cprop.Ax = [prop.Def, prop.Pos, {'UIContextMenu'}];
cprop.Li = {'BeingDeleted','BusyAction','ButtonDownFcn','Color','CreateFcn','DeleteFcn','DisplayName','EraseMode','HandleVisibility','HitTest','Interruptible','LineStyle','LineWidth','Marker','MarkerEdgeColor','MarkerFaceColor','MarkerSize','Parent','Selected','SelectionHighlight','Tag','UIContextMenu','UserData','Visible','XData','YData','ZData'};
cprop.Sf = {'AlphaData','AlphaDataMapping','CData','CDataMapping','DisplayName','EdgeAlpha','EdgeColor','EraseMode','FaceAlpha','FaceColor','LineStyle','LineWidth','Marker','MarkerEdgeColor','MarkerFaceColor','MarkerSize','MeshStyle','XData','YData','ZData','FaceLighting','EdgeLighting','BackFaceLighting','AmbientStrength','DiffuseStrength','SpecularStrength','SpecularExponent','SpecularColorReflectance','VertexNormals','NormalMode','ButtonDownFcn','Selected','SelectionHighlight','Tag','UIContextMenu','UserData','Visible','Parent','XDataMode','XDataSource','YDataMode','YDataSource','CDataMode','CDataSource','ZDataSource'};
cprop.St = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','HorizontalAlignment'}];
cprop.Pb = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu','CData'}];
cprop.Tb = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu','CData'}];
cprop.Rb = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu'}];
cprop.Cb = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu'}];
cprop.Ed = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu','HorizontalAlignment','Min','Max'}];
cprop.Lb = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu','Min','Max'}];
cprop.Pu = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu'}];
cprop.Sl = [prop.Def, {'Style'}, prop.Pos, prop.Font, prop.Color, prop.Str, {'Enable','UIContextMenu','Min','Max','SliderStep'}];
cprop.Ta = [prop.Def, prop.Pos, prop.Font, prop.Color, {'ColumnEditable','ColumnFormat','ColumnName','ColumnWidth','Data','Enable','RearrangeableColumns','RowName','RowStriping','TooltipString','UIContextMenu'}];
cprop.To = [prop.Def];
cprop.Pt = [prop.Def, {'TooltipString','CData','Enable','Separator'}];
cprop.Tt = [prop.Def, {'TooltipString','CData','Enable','Separator','State'}];
end


%-------------------------------------------------------------------------------
function dprop = default_prop_values()

dprop = struct( ...
  'MenuBar'             , 'figure', ...
  'NumberTitle'         , 'on', ...
  'Resize'              , 'off', ...
  'UIContextMenu'       , [], ...
  'FontAngle'           , 'normal', ...
  'FontName'            , 'MS Sans Serif', ...
  'FontSize'            , 8, ...
  'FontUnits'           , 'points', ...
  'FontWeight'          , 'normal', ...
  'ForegroundColor'     , [0 0 0], ...
  'BackgroundColor'     , get(0,'DefaultUicontrolBackgroundColor'), ...
  'TitlePosition'       , 'lefttop', ...
  'BorderType'          , 'etchedin', ...
  'BorderWidth'         , 1, ...
  'HighlightColor'      , [1 1 1], ...
  'ShadowColor'         , [0.5 0.5 0.5], ...
  'HorizontalAlignment' , 'center', ...
  'TooltipString'       , '', ...
  'CData'               , [], ...
  'Enable'              , 'on', ...
  'SliderStep'          , [.01 .1], ...
  'Min'                 , 0, ...
  'Max'                 , 1, ...
  'UserData'            , [], ...
  'BeingDeleted'        , 'off', ...
  'BusyAction'          , 'queue', ...
  'ColumnEditable'      , [], ...
  'ColumnFormat'        , [], ...
  'ColumnName'          , 'numbered', ...
  'ColumnWidth'         , 'auto', ...
  'Data'                , {cell(4,2)}, ...
  'RearrangeableColumns', 'off', ...
  'RowName'             , 'numbered', ...
  'RowStriping'         , 'on', ...
  'Visible'             , 'on', ...
  'String'              , '', ...
  'Separator'           , 'off', ...
  'State'               , 'off');
end

Contact us at files@mathworks.com