function varargout = buildRun1GUI(varargin)
% function varargout = buildRun1GUI(varargin)
% Purpose: There are three methods for which the GUI can be used to generate
%          the user-defined GUI:
%          1) User provide menu definition thru a GUI interactive input
%             gui4gui.fig. By selecting the GUI generation button, the
%             collected menu definition data will be passed to this
%             function to generate the user GUI.
%          2) User enters menu definition directly into a file. Then, the
%             user manually run this program to generate the user GUI.
%          3) Combination of the above two methods.
% varargin: Caller provides menu definition data as a structure GID.
%           Only varargin{1} is relevant, any additional input will be
%           ignored. The caller is usually gui4gui. It collects GID
%           interactively (or semi-interactively) and then calls genGUI to
%           generate the application GUI.
% If nargin == 0, then this GUI assumes that the menu definition data has
% already been generated and saved in gui4gui_input.mat. It uses this
% file to generate the GUI without going thru gui4gui
% Date created: May 21, 2009
% Kadin Tseng, SCV, Boston University
version = '1.0';

if nargin > 0 & isstruct(varargin{1})
  GID = varargin{1};
else
% loads the data structure that defines the menus
% for the MODE code, there are two situations where this GUI generator might
% be used: Real time task or Fixed duration task. They are both very similar
% in the input requirement but nevertheless requires distinctive m-files
%  varargin{1}
  load run1_inputfile;
%  eval('load varargin{1}');
end

% additional GUI settings:
% fontsize and fontweight for the RUN button
% The title fontsize is 2 sizes larger than the basic user setting
fontsize_title = GID.fontsize + 2;
fontweight_title = GID.fontweight;
fontsize_run = GID.fontsize + 2;
fontweight_run = GID.fontweight;

fid = fopen([GID.guiName '.m'],'w+');

fprintf(fid,'function %s(varargin)\n',GID.guiName);
fprintf(fid,'fh = figure(''Visible'',''off'', ...\n');
fprintf(fid,'            ''HandleVisibility'',''callback'', ...\n');
fprintf(fid,'            ''NumberTitle'',''off'', ...  %% turns off MATLAB GUI window title\n');
fprintf(fid,'            ''Name'',''%s'', ...    %% now, define my own\n',GID.guiName);
fprintf(fid,'            ''Units'',''normalized'', ...\n');
fprintf(fid,'            ''Position'',[%d %d %d %d], ...\n',GID.position);
fprintf(fid,'            ''Color'',''%s'', ...   %% match bg of MODE_new.jpg\n',GID.bgcolor);
fprintf(fid,'            ''Resize'',''%s'');\n',GID.resize);

fprintf(fid,'set(fh,''MenuBar'',''none'');  %% removes MATLAB default menu bar\n');

fprintf(fid,'x0 = 0.1; y0 = 0.85;\n');
fprintf(fid,'x0run = 0.825; y0run = 0.075; %% lower-left corner coord. of the run button\n');
fprintf(fid,'dxst1 = 0.075; dyst1 = 0.05;  %% for static text 1\n');
fprintf(fid,'dxet1 = 0.100; dyet1 = 0.05;  %% for edit text 1\n');
fprintf(fid,'dxst2 = 0.400; dyst2 = 0.10;  %% for static text 2\n');
fprintf(fid,'dxpb1 = 0.050; dypb1 = 0.05;  %% for PDF logo pushbuttons\n');
fprintf(fid,'dxrun = 0.100; dyrun = 0.075; %% for "Run" pushbutton\n');

fprintf(fid,'%% First, create a Heading for the secondary GUI with a static text box\n');
fprintf(fid,'dx = 0.6; dy = 0.125;\n');

fprintf(fid,'st0h = uicontrol(fh, ...\n');
fprintf(fid,'            ''style'',''text'', ...\n');
brkpt = regexp(GID.title,'!');  % check for "!", definde here as line break

%%%% to do: regexprep would be more direct; implementation problem with fprintf

numLines = length(brkpt) + 1;
switch numLines
  case 1    % one-line title
    fprintf(fid,'            ''String'',[''%s''], ...\n',GID.title);
  case 2    % two-line title
    fprintf(fid,'            ''String'',[''%s'' char(10) ''%s''], ...\n',GID.title(1:brkpt-1),GID.title(brkpt+1:end));
  case 3    % three-line title
    fprintf(fid,'            ''String'',[''%s'' char(10) ''%s'' char(10) ''%s''], ...\n', ...
      GID.title(1:brkpt(1)-1),GID.title(brkpt(1)+1:brkpt(2)-1),GID.title(brkpt(2)+1:end));
  otherwise
    disp('Title with more than 3 lines is not anticipated.')
    disp(' "!" is reserved by the GUI builder to force a new line.')
    disp('Make sure not to use it as part of your GUI title text.')
    return
end
fprintf(fid,'            ''Units'',''normalized'', ...\n');
fprintf(fid,'            ''Position'',[x0,y0,dx,dy], ...\n');
fprintf(fid,'            ''FontSize'',%d, ...\n',fontsize_run);
fprintf(fid,'            ''FontWeight'',''%s'');\n',fontweight_run);
fprintf(fid,'\n');
fprintf(fid,'%% Create static box, edit box, static box, logo (that points to a doc; optional)\n');
fprintf(fid,'y0 = y0 - dy*1.05; space = dxst1*0.20;\n');
nlines = size(GID.string,1);
for line=1:nlines
str = GID.string(line,:);
fprintf(fid,'data.str{%d} = ''%s'';\n',line,str{1});
fprintf(fid,'data.default{%d} = %f;\n',line,str2double(str{2}));
fprintf(fid,'  st1h(%d) = uicontrol(fh,''style'',''text'', ...\n',line);
fprintf(fid,'      ''String'',''%s'', ...\n',str{1});
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[x0,y0,dxst1,dyst1], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'');\n',GID.fontweight);
fprintf(fid,'  et1h(%d) = uicontrol(fh,''Style'',''edit'', ...\n',line);
fprintf(fid,'      ''String'',''%s'', ...\n',str{2});
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[x0+dxst1+space,y0,dxet1,dyet1], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'', ...\n','normal');
fprintf(fid,'      ''callback'',{@edit1_Callback ''%s''});\n',str{1});
fprintf(fid,'  st2h(%d) = uicontrol(fh,''style'',''text'', ...\n',line);
fprintf(fid,'      ''String'',''%s'', ...\n',str{3});
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[x0+dxst1+dxet1+space*2,y0-0.02,dxst2,dyst2], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'');\n',GID.fontweight);
fprintf(fid,'  pb1h(%d) = uicontrol(fh,''Style'',''pushbutton'', ...\n',line);
fprintf(fid,'      ''String'',''PDF'', ...\n');
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[x0+dxst1+dxet1+dxst2+space*3,y0,dxpb1,dypb1], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'', ...\n',GID.fontweight);
fprintf(fid,'      ''callback'',{@opendoc1_Callback ''%s''});\n',str{4});
fprintf(fid,'  y0 = y0 - max([dyst1 dyst2 dyet1 dypb1])*1.1;\n');

end   % end of "line" loop

fprintf(fid, ...
    ['%% save the edit text handles to data\n' ...
     'data.et1h = et1h(1:end);\n']);
fprintf(fid,'for i=1:length(data.str)\n');
fprintf(fid,'   eval([''data.'' data.str{i} ''= data.default{i};'']);\n');
fprintf(fid,'end\n');

fprintf(fid,'data.guiName = ''%s'';\n',GID.guiName);
fprintf(fid,'setappdata(fh, ''myData'', data);\n');

% Foonotes and RUN button
fprintf(fid,'%%align(st0h,''HorizontalAlignment'',''center'');\n');
fprintf(fid,'st3h = uicontrol(fh,''style'',''text'', ...\n');
fprintf(fid,'      ''String'',''%s'', ...\n',GID.fn1);
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[0.05,0.08,0.60,0.05], ...\n');
fprintf(fid,'      ''HorizontalAlignment'',''Left'', ...\n');
fprintf(fid,'      ''foregroundColor'',[1 0 0], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'');\n', GID.fontweight);
fprintf(fid,'st4h = uicontrol(fh,''style'',''text'', ...\n');
fprintf(fid,'      ''String'',''%s'', ...\n',GID.fn2);
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[0.05,0.02,0.60,0.05], ...\n');
fprintf(fid,'      ''HorizontalAlignment'',''Left'', ...\n');
fprintf(fid,'      ''foregroundColor'',[1 0 0], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',GID.fontsize);
fprintf(fid,'      ''FontWeight'',''%s'');\n',GID.fontweight);
fprintf(fid,'\n');

% this is for either RT or FD (by virtue of GID value)advanced run

fprintf(fid,'runh = uicontrol(fh,''Style'',''pushbutton'', ...\n');
fprintf(fid,'      ''String'',''RUN'', ...\n');
fprintf(fid,'      ''Units'',''normalized'', ...\n');
fprintf(fid,'      ''Position'',[x0run,y0run,dxrun,dyrun], ...\n');
fprintf(fid,'      ''FontSize'',%d, ...\n',fontsize_run);
fprintf(fid,'      ''FontWeight'',''%s'', ...\n',fontweight_run);
fprintf(fid,'      ''callback'',{@run1_Callback ''%s''});\n',GID.run);
fprintf(fid,'PDFbuttons(pb1h);\n');
fprintf(fid,'\n\n');

% use the bgcolor of uicontrol for the GUI figure
fprintf(fid,'etbgcolor = get(et1h(1),''BackgroundColor'');\n');
fprintf(fid,'set(fh,''Color'',etbgcolor);\n');
% Now, turns on the GUI figure
fprintf(fid,'set(fh,''Visible'',''on'');\n');
fprintf(fid,'\n\n');

% Callback functions needed fot this GUI are generated below
% callback function of the "doc1" type
fprintf(fid, ...
    ['function opendoc1_Callback(hObject,eventdata,varargin)\n' ...
     '%% hObject    handle to Exit_menu_item (see GCBO)\n' ...
     '%% eventdata  reserved - to be defined in a future version of MATLAB\n' ...
     'open(varargin{1});\n' ...
     '\n\n']);

% edit text callback
fprintf(fid, ...
  ['function edit1_Callback(hObject, eventdata, varargin)\n' ...
   '%% hObject    handle to edit1 (see GCBO)\n' ...
   '%% eventdata  reserved - to be defined in a future version of MATLAB\n' ...
   '\n' ...
   '%% Hints: get(hObject,''String'') returns contents of edit1 as text\n' ...
   '%%        str2double(get(hObject,''String'')) returns contents of edit1 as a double\n' ...
   '\n' ...
   'fh = get(hObject,''parent'');\n' ...
   'data = getappdata(fh, ''myData'');\n' ...
   'value = str2num(get(hObject,''String''));\n' ...
   'eval([''data.'' varargin{1} ''= value;'']);\n' ...
   'setappdata(fh,''myData'',data);\n' ...
   '\n\n']);

% RUN callback
fprintf(fid, ...
  ['function run1_Callback(hObject, eventdata, varargin)\n' ...
   '%% hObject    handle to run1_Callback \n' ...
   '%% eventdata  reserved - to be defined in a future version of MATLAB\n' ...
   '%% Hints: get(hObject,''String'') returns contents of edit1 as text\n' ...
   '%%        str2double(get(hObject,''String'')) returns contents of edit1 as a double\n' ...
   'fh = get(hObject,''parent'');\n' ...
   'data = getappdata(fh, ''myData'');\n']);
   fprintf(fid,'for i=1:length(data.str)\n');
   fprintf(fid,'   eval([data.str{i} ''= data.'' data.str{i} '';'']);  %% e.g., A9 = data.A9;\n');
   fprintf(fid,'end\n');

fprintf(fid, ...
  ['%% Prevent user from changing the contents of edit boxes\n' ...
   'editBoxEnable2(data,''Off'');\n' ...
   'old_color=get(hObject,''BackgroundColor''); %% save original button color\n' ...
   'set(hObject, ''BackgroundColor'', [1 0 0]); %% Change button color\n' ...
   'set(hObject, ''String'', ''running ...'');\n' ...
   '%% open(''RTcaption.pdf'');\n' ...
   'drawnow    %% to make sure that the "Run" button change color right away\n' ...
   'eval(varargin{1})   %% run the m-file specified by varargin{1}\n']);
fprintf(fid, ...
  ['set(hObject, ''String'', ''Run'');\n' ...
   'set(hObject, ''BackgroundColor'', old_color);\n' ...
   'editBoxEnable2(data,''On'');\n']);
fprintf(fid,'\n\n');

fclose(fid);
disp([char(10) '***** The ' GID.guiName ' GUI is built successfully *****' char(10)]);


function F = conj( F )
%CONJ Complex conjugate of a DISKFUNV.
%   CONJ(F) returns the complex conjugate of F. For a complex F, CONJ(F) =
%   REAL(F) - i*IMAG(F).
%
%   Since only real DISKFUNV objects are supported, the result of this
%   function is always the original function F.
%
%   See also DISKFUNV/IMAG, DISKFUNV/REAL.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Empty check:
if ( isempty( F ) )
    return
end

% Take conj part of each component:
F.components = cellfun( @conj, F.components, 'UniformOutput', false );

end


function metadata = psdreadheader(fid)
%PSDREADHEADER  Read the metadata from an open PSD file.
%   METADATA = PSDREADHEADER(FID) fread metadata from an Adobe Photoshop
%   PSD file using the file handle FID, which must already be opened.

%   Author: Jeff Mather
%   Copyright 1984-2004 The MathWorks, Inc.

fids = fopen('all');

if (isempty(find(fid == fids)))
    error('psdreadheader:badFID', 'Bad file ID.');
end

% Read the PSD header.
metadata.FormatSignature = fread(fid, 4, 'uint8=>char');
if (~isequal(metadata.FormatSignature', '8BPS'))
    fclose(fid);
    error('impsdinfo:badSignature', 'Format signature mismatch (%s).', ...
          metadata.FormatSignature)
end

metadata.FormatVersion = fread(fid, 1, 'uint16=>uint16');
if (metadata.FormatVersion ~= 1)
    error('impsdinfo:badVersion', 'Bad PSD version number (%d).', ...
          metadata.FormatVersion)
end

fseek(fid, 6, 'cof');  % Reserved
metadata.NumSamples = fread(fid, 1, 'uint16');
metadata.Rows = fread(fid, 1, 'uint32');
metadata.Columns = fread(fid, 1, 'uint32');
metadata.BitsPerSample = fread(fid, 1, 'uint16=>uint16');
metadata.ColorMode = decodeColorMode(fread(fid, 1, 'uint16=>uint16'));

% Read color mode data, image resources, and layer/mask information.
blockLen = fread(fid, 1, 'uint32');
metadata.ColorModeData.Length = blockLen;
if (blockLen > 0)
    metadata.ColorModeData.Data = fread(fid, blockLen, 'uint8=>uint8');
else
    metadata.ColorModeData.Data = [];
end

blockLen = fread(fid, 1, 'uint32');
metadata.ImageResources.Length = blockLen;
if (blockLen > 0)
    metadata.ImageResources.Data = fread(fid, blockLen, 'uint8=>uint8');
else
    metadata.ImageResources.Data = [];
end

blockLen = fread(fid, 1, 'uint32');
metadata.LayersAndMasks.Length = blockLen;
if (blockLen > 0)
    metadata.LayersAndMasks.Data = fread(fid, blockLen, 'uint8=>uint8');
else
    metadata.LayersAndMasks.Data = [];
end

% Read the image data block.
metadata.Compression = fread(fid, 1, 'uint16');

function modeString = decodeColorMode(modeNum)
%DECODECOLORMODE  Convert a numeric color mode to a string.

switch (modeNum)
case 0
    modeString = 'Bitmap';
case 1
    modeString = 'Grayscale';
case 2
    modeString = 'Indexed color';
case 3
    modeString = 'RGB';
case 4
    modeString = 'CMYK';
case 7
    modeString = 'Multichannel color';
case 8
    modeString = 'Duotone';
case 9
    modeString = 'Lab';
otherwise
    modeString = modeNum;
end


classdef mp_table
%MP_TABLE  Very basic TABLE class for Octave or older Matlab.

%   MATPOWER
%   Copyright (c) 2021, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

    properties (Access=protected)
        Properties = struct('VariableNames',  {{}}, ...
                            'VariableValues', {{}}, ...
                            'RowNames',       {{}}, ...
                            'DimensionNames', {{}}    );
    end     %% properties

    methods
        function obj = mp_table(varargin)
            args = varargin;

            if nargin
                %% extract named arguments
                [var_names, row_names, dim_names, args] = ...
                    extract_named_args(obj, args);

                %% set default variable names
                nv = length(args);          %% number of variables
                if length(var_names) < nv
                    for k = nv:-1:length(var_names)+1
                        var_names{k} = inputname(k);
                        if isempty(var_names{k})
                            var_names{k} = sprintf('Var%d', k);
                        end
                    end
                end

                %% set default dimension names
                if isempty(dim_names)
                    dim_names = {'Row', 'Variables'};
                end

                %% check dimensions
                if length(var_names) > nv
                    warning('mp_table: ignoring %d extra VariableNames provided', length(var_names)-nv);
                end
                nr = size(args{1}, 1);      %% number of rows
                for k = 2:nv
                    if size(args{k}, 1) ~= nr
                        error('mp_table: variable %d expected to have %d rows', k, nr);
                    end
                end

                %% set table properties
                obj.Properties.VariableNames = var_names;
                obj.Properties.DimensionNames = dim_names;
                obj.Properties.RowNames = row_names;
                obj.Properties.VariableValues = args;
                obj.Properties.Map = cell2struct(num2cell(1:nv), var_names, 2);
            end
        end

        function new_obj = copy(obj)
            new_obj = eval(class(obj));  %% create new object

            %% make copies of properties
            if have_feature('octave')
                s1 = warning('query', 'Octave:classdef-to-struct');
                warning('off', 'Octave:classdef-to-struct');
            end
            props = fieldnames(obj);
            if have_feature('octave')
                warning(s1.state, 'Octave:classdef-to-struct');
            end
            for k = 1:length(props)
                new_obj.(props{k}) = obj.(props{k});
            end

            %% make copies of values
            for k = 1:length(obj.Properties.VariableValues)
                if isobject(obj.Properties.VariableValues{k}) && ...
                        ismethod(obj.Properties.VariableValues{k}, 'copy')
                    new_obj.Properties.VariableValues{k} = ...
                        copy(obj.Properties.VariableValues{k});
                end
            end
        end

        %% not really useable until Octave implements istable()
        function TorF = istable(obj)
            TorF = true;
        end

        function varargout = size(obj, dim)
            varargout = cell(1, nargout);
            w = length(obj.Properties.VariableValues);
            if w
                h = size(obj.Properties.VariableValues{1}, 1);
            else
                h = 0;
            end
            if nargin == 2
                if dim == 1
                  varargout{1} = h;
                elseif dim == 2
                  varargout{1} = w;
                else
                  varargout{1} = 1;
                end
            elseif nargout == 0 || nargout == 1
                varargout{1} = [h, w];
            else
                varargout{1} = h;
                varargout{2} = w;
                [varargout{3:end}] = deal(1);
            end
        end

        function TorF = isempty(obj)
            TorF = prod(size(obj)) == 0;
        end

        function N = end(obj, k, n)
            N = size(obj, k);
        end

        function n = numArgumentsFromSubscript(obj, s, indexingContext)
            n = 1;
        end

        function n = numel(obj, varargin)
            %% needed to avoid error when doing T{r1:rN, c} = b;
            %% see https://github.com/apjanke/octave-tablicious/issues/80#issuecomment-855198281
            n = 1;
        end

        function b = subsref(obj, s)
            switch s(1).type
                case '.'
                    if strcmp(s(1).subs, 'Properties')
                        b = obj.Properties;
                    else
                        p = obj.Properties;
                        b = p.VariableValues{p.Map.(s(1).subs)};
                    end
                case '()'
                    r = s(1).subs{1};
                    if length(s(1).subs) > 1
                        c = s(1).subs{2};
                    else
                        c = ':';
                    end
                    var_names = obj.Properties.VariableNames(1,c);
                    %% Octave has issues with this ...
                    % var_vals = cellfun(@(x)x(r,:), ...
                    %     obj.Properties.VariableValues(c), 'UniformOutput', 0);
                    %% ... so we use explicit subsref instead ...
                    ss = struct('type', '()', 'subs', {{r, ':'}});
                    var_vals = cellfun(@(x)subsref(x, ss), ...
                        obj.Properties.VariableValues(c), 'UniformOutput', 0);
                    dim_names = obj.Properties.DimensionNames;
                    if isempty(obj.Properties.RowNames)
                        row_names = {};
                    else
                        row_names = obj.Properties.RowNames(r);
                    end
                    b = mp_table(var_vals{:}, ...
                        'VariableNames', var_names, 'RowNames', row_names, ...
                        'DimensionNames', dim_names);
                case '{}'
                    a = horzcat(obj.Properties.VariableValues{s(1).subs{2}});
                    b = a(s(1).subs{1}, :);
            end
            if length(s) > 1    %% recurse
                b = subsref(b, s(2:end));
            end
        end

        function obj = subsasgn(obj, s, b)
            R = length(s) > 1;      %% need to recurse
            switch s(1).type
                case '.'
                    if strcmp(s(1).subs, 'Properties')
                        if R
                            obj.Properties = ...
                                subsasgn(obj.Properties, s(2:end), b);
                        else
                            obj.Properties = b;
                        end
                    else
                        if isfield(obj.Properties.Map, s(1).subs)
                            idx = obj.Properties.Map.(s(1).subs);
                            if R
                                obj.Properties.VariableValues{idx} = ...
                                    subsasgn(obj.Properties.VariableValues{idx}, ...
                                        s(2:end), b);
                            else
                                obj.Properties.VariableValues{idx} = b;
                            end
                        else    %% new variable
                            if R
                                error('mp_table/subsagn: cannot index new variable ''%s''', s(1).subs);
                            end
                            %% check size compatibility
                            if size(b, 1) ~= size(obj, 1)
                                error('mp_table/subsagn: number of rows (%d) in new variable ''%s'' does not match height of table (%d)', size(b, 1), s(1).subs, size(obj, 1));
                            end
                            %% add variable
                            idx = size(obj, 2) + 1;
                            obj.Properties.VariableNames{idx} = s(1).subs;
                            obj.Properties.Map.(s(1).subs) = idx;
                            obj.Properties.VariableValues{idx} = b;
                        end
                    end
                case '()'
                    nv = size(b, 2);
                    idx = s(1).subs{2};
                    if ischar(idx)
                        if length(idx) == 1 && idx == ':'
                            idx = [1:nv];
                        else        %% for 'a:b' syntax as a char array
                            idx = eval(['[' idx ']'])
                        end
                    end
                    if nv
                        ss = struct('type', '{}', 'subs', {{':', 0}});
                        for k = 1:nv
                            ss(1).subs{2} = k;
                            obj.Properties.VariableValues{idx(k)}(s(1).subs{1}, :) = ...
                                subsref(b, ss);     %% = b{:, k};
                        end
                    else    %% delete variable
                        obj.Properties.VariableNames(idx) = [];
                        obj.Properties.VariableValues(idx) = [];
                        %% rebuild map
                        nv = size(obj, 2);
                        obj.Properties.Map = cell2struct(num2cell(1:nv), obj.Properties.VariableNames, 2);
                    end
                    if R
                        error('mp_table/subasgn: sub-indexing following {}-indexing not supported');
                    end
                case '{}'
                    idx = s(1).subs{2};
                    if ischar(idx)
                        if length(idx) == 1 && idx == ':'
                            idx = [1:size(obj, 2)];
                        else        %% for 'a:b' syntax as a char array
                            idx = eval(['[' idx ']'])
                        end
                    end
                    j = 1;  %% col index in b
                    for k = 1:length(idx)
                        %% get num cols for var k
                        nc = size(obj.Properties.VariableValues{idx(k)}, 2);
                        if nc > 1
                            obj.Properties.VariableValues{idx(k)}(s(1).subs{1}, :) = b(:, j:j+nc-1);
                        else
                            obj.Properties.VariableValues{idx(k)}(s(1).subs{1}, :) = b(:, j);
                        end
                        j = j+nc;
                    end
                    if R
                        error('mp_table/subasgn: sub-indexing following ()-indexing not supported');
                    end
            end
        end

        function obj = horzcat(obj, varargin)
            [nr, nv] = size(obj);
            nvn = length(obj.Properties.VariableNames); %% num variable names
            nrn = length(obj.Properties.RowNames);      %% num row names

            %% for each table to append
            for j = 1:length(varargin)
                Tj = varargin{j};       %% table being appended
                [nrj, nvj] = size(Tj);
                nrnj = length(Tj.Properties.RowNames);      %% num row names Tj

                %% check for consistent number of rows
                if nrj ~= nr
                    error('mp_table/horzcat: number of rows in arg %d (%d) does not match that in arg 1 (%d)', ...
                        j+1, nrj, nr);
                end

                %% check for row name mismatch
                if nrn          %% obj has row names
                    if nrnj && ~isequal(obj.Properties.RowNames, ...
                                         Tj.Properties.RowNames)
                        for k = 1:nrn
                            if ~strcmp(obj.Properties.RowNames{k}, ...
                                        Tj.Properties.RowNames{k})
                                error('mp_table/horzcat: name of row %d in arg %d (%s) does not match the one in arg 1 (%s)', ...
                                    k, j+1, Tj.Properties.RowNames{k}, ...
                                        obj.Properties.RowNames{k});
                            end
                        end
                    end
                elseif nrnj     %% Tj has row names, but obj does not (use them)
                    obj.Properties.RowNames = Tj.Properties.RowNames;
                    nrn = nrnj;
                end
                var_names = Tj.Properties.VariableNames;

                %% stack variable names and check for duplicates
                obj.Properties.VariableNames = ...
                    [obj.Properties.VariableNames, var_names];
                nvn = nvn + nvj;    %% update num variable names
                if length(unique(obj.Properties.VariableNames)) < nvn
                    [~, ia, ~] = unique(obj.Properties.VariableNames);
                    k = find(ismember(1:nvn, ia));
                    error('mp_table/horzcat: duplicate variable name ''%s''', ...
                        obj.Properties.VariableNames{k(1)});
                end

                %% horzcat var values
                obj.Properties.VariableValues = ...
                    [ obj.Properties.VariableValues, ...
                       Tj.Properties.VariableValues ];
                nv = length(obj.Properties.VariableValues);

                %% update Properties.Map
                obj.Properties.Map = cell2struct(num2cell(1:nv), ...
                    obj.Properties.VariableNames, 2);
            end
        end

        function obj = vertcat(obj, varargin)
            [nr, nv] = size(obj);
            nvn = length(obj.Properties.VariableNames); %% num variable names
            nrn = length(obj.Properties.RowNames);      %% num row names

            %% for each table to append
            for j = 1:length(varargin)
                Tj = varargin{j};       %% table being appended
                [nrj, nvj] = size(Tj);
                nvnj = length(Tj.Properties.VariableNames); %% num var names Tj

                %% check for consistent number of variables
                if nvj ~= nv
                    error('mp_table/vertcat: number of variables in arg %d (%d) does not match that in arg 1 (%d)', ...
                        j+1, nvj, nv);
                end

                %% check for variable name mismatch
                if ~isequal(obj.Properties.VariableNames, ...
                             Tj.Properties.VariableNames)
                    for k = 1:nvn
                        if ~strcmp(obj.Properties.VariableNames{k}, ...
                                    Tj.Properties.VariableNames{k})
                            error('mp_table/vertcat: name of variable %d in arg %d (%s) does not match the one in arg 1 (%s)', ...
                                k, j+1, Tj.Properties.VariableNames{k}, ...
                                    obj.Properties.VariableNames{k});
                        end
                    end
                end

                %% create missing row names if any exist
                row_names = Tj.Properties.RowNames;
                if nrn                      %% obj has row names, Tj does not
                    if length(row_names) == 0
                        %% create names for rows of Tj
                        row_names = cell(nrj, 1);
                        for kk = 1:nrj
                            row_names{kk} = sprintf('Row%d', kk+nrn);
                        end
                    end
                elseif length(row_names)    %% Tj has row names, obj does not
                    %% create names for rows of obj
                    obj.Properties.RowNames = cell(nr, 1);
                    for kk = 1:nr
                        obj.Properties.RowNames{kk} = sprintf('Row%d', kk);
                    end
                end
                nrn = length(obj.Properties.RowNames);

                %% stack row names and check for duplicates
                if nrn
                    obj.Properties.RowNames = ...
                        [obj.Properties.RowNames; row_names];
                    nrn = nrn + nrj;    %% update num row names
                    if length(unique(obj.Properties.RowNames)) < nrn
                        [~, ia, ~] = unique(obj.Properties.RowNames);
                        k = find(ismember(1:nrn, ia));
                        error('mp_table/horzcat: duplicate row name ''%s''', ...
                            obj.Properties.RowNames{k(1)});
                    end
                end

                %% for each variable
                for k = 1:nv
                    %% vertcat var values
                    obj.Properties.VariableValues{k} = ...
                        [ obj.Properties.VariableValues{k}; ...
                           Tj.Properties.VariableValues{k} ];
                end
            end
        end

        function [var_names, row_names, dim_names, args] = ...
                extract_named_args(obj, args)
            var_names = {};
            row_names = {};
            dim_names = {};
            for k = length(args)-1:-1:1
                if ischar(args{k})
                    switch args{k}
                        case 'VariableNames'
                            var_names = args{k+1};
                            args(k:k+1) = [];
                        case 'RowNames'
                            row_names = args{k+1};
                            args(k:k+1) = [];
                        case 'DimensionNames'
                            dim_names = args{k+1};
                            args(k:k+1) = [];
                    end
                end
            end
        end

        function display(obj)
            allrows = 1;

            [nr, nv] = size(obj);

            %% rows to display
            max_nr = 25;
            first_last = 10;
            if nr <= max_nr || allrows
                rr = [1:nr]';
            else
                rr = [1:first_last nr-first_last+1:nr]';
            end

            %% var names
            vn = obj.Properties.VariableNames;
            rn = obj.Properties.RowNames;

            %% col_widths
            if isempty(rn)
                cwr = 0;
            else
                cwr = max(cellfun(@length, rn));    %% col width for row names
            end
            for v = nv:-1:1
                cw(v) = length(vn{v});  %% actual column width
                cwv(v) = 0;             %% column width for displayed values
                vv = obj.Properties.VariableValues{v};
                if size(vv, 2) > 1 || isa(vv, 'mp_table') || isa(vv, 'table')
                    s = sprintf('1x%d %s' , size(vv, 2), class(vv));
                    len_s = length(s);
                    if len_s > cw(v);
                        cw(v) = len_s;
                    end
                    if len_s > cwv(v);
                        cwv(v) = len_s;
                    end
                else
                    if iscell(vv)
                        for r = 1:length(rr)
                            s = sprintf('''%s''', vv{rr(r)});
                            len_s = length(s);
                            if len_s > cw(v);
                                cw(v) = len_s;
                            end
                            if len_s > cwv(v);
                                cwv(v) = len_s;
                            end
                        end
                    else
                        for r = 1:length(rr)
                            if isempty(vv)
                                s = '[]';
                            else
                                s = sprintf('%g', vv(rr(r), 1));
                            end
                            len_s = length(s);
                            if len_s > cw(v);
                                cw(v) = len_s;
                            end
                            if len_s > cwv(v);
                                cwv(v) = len_s;
                            end
                        end
                    end
                end
                spc{v} = repmat(' ', 1, floor((cw(v)-cwv(v))/2));
            end

            fprintf('\n %dx%d %s\n\n', nr, nv, class(obj));

            %% display var names & lines
            fprintf('  %s', repmat(' ', 1, cwr));
            for v = 1:nv
                fmt = sprintf('  %%-%ds', cw(v));
                name = sprintf('%s', vn{v});
                spcs = repmat(' ', 1, floor((cw(v)-length(name))/2));
                fprintf(fmt, [spcs name]);
            end
            fprintf('\n');
            fprintf('  %s', repmat(' ', 1, cwr));
            for v = 1:nv
                s = repmat('-', 1, cw(v));
                fprintf('  %s', s);
            end
            fprintf('\n');

            %% display var values
            for r = 1:length(rr)
                %% row names
                if isempty(rn)
                    fprintf('  ');
                else
                    fmt = sprintf('  %%-%ds', cwr);
                    fprintf(fmt, rn{rr(r)});
                end

                %% variable values
                for v = 1:nv
                    vv = obj.Properties.VariableValues{v};
                    if size(vv, 2) > 1 || isa(vv, 'mp_table') || isa(vv, 'table')
                        val = sprintf('%s1x%d %s', spc{v}, size(vv, 2), class(vv));
                        fmt = sprintf('  %%-%ds', cw(v));
                    else
                        if iscell(vv)
                            val = sprintf('%s''%s''', spc{v}, vv{rr(r), 1});
                            fmt = sprintf('  %%-%ds', cw(v));
                        else
                            if isempty(vv)
                                val = sprintf('[]%s', spc{v});
                            else
                                val = sprintf('%g%s', vv(rr(r), 1), spc{v});
                            end
                            fmt = sprintf('  %%%ds', cw(v));
                        end
                    end
                    fprintf(fmt, val);
                end
                fprintf('\n');

                %% print continuation dots if not displaying all rows
                if nr > length(rr) && r == first_last
                    for k = 1:3
                        for v = 1:nv
                            spcs = repmat(' ', 1, floor(cwv(v)/2));
                            if iscell(vv)
                                dot = sprintf('%s%s.', spc{v}, spcs);
                                fmt = sprintf('  %%-%ds', cw(v));
                            else
                                dot = sprintf('.%s%s', spcs, spc{v});
                                fmt = sprintf('  %%%ds', cw(v));
                            end
                            fprintf(fmt, dot);
                        end
                        fprintf('\n');
                    end
                end
            end
            fprintf('\n');
        end
    end     %% methods
end         %% classdef


function test_bug1262

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_read_header ft_read_data ft_read_event

% Quick and dirty sanity check for reading of fcdc_buffer_offline data.

% Example data generated with sine example, saved with record.exe:
dirname = dccnpath('/home/common/matlab/fieldtrip/data/test/bug1262/0001');

hdr = ft_read_header(dirname);
assert(hdr.nChans == 16);
assert(hdr.nSamples == 1216);

dat = ft_read_data(dirname);
assert(all(size(dat) == [hdr.nChans, hdr.nSamples]));

evt = ft_read_event(dirname);
assert(numel(evt) == 0);  % there are no events


function [inputImages, inputSignals, choices] = signalSorter(inputImages,inputSignals,varargin)
	% Displays a GUI for sorting images (e.g. cells) and their associated signals (e.g. fluorescence activity traces). Also does preliminary sorting based on image/signal properties if requested by user.
	% See following URL for details of GUI and tips on manual sorting: https://github.com/bahanonu/calciumImagingAnalysis/wiki/Manual-cell-sorting-of-cell-extraction-outputs.
	% Biafra Ahanonu
	% started: 2013.10.08
	% Dependent code
		% getOptions.m, createObjMap.m, removeSmallICs.m, identifySpikes.m, etc., see repository
	% inputs
		% inputImages - [x y N] matrix where N = number of images, x/y are dimensions. Use permute(inputImages,[2 3 1]) if you use [N x y] for matrix indexing.
			% Alternatively, make inputImages = give path to NWB file and inputSignals = [] for signalSorter to automatically load NWB files.
		% inputSignals - [N time] matrix where N = number of signals (traces) and time = frames.
		% inputID - obsolete, kept for compatibility, just input empty []
		% nSignals - obsolete, kept for compatibility
	% outputs
		% inputImages - [N x y] matrix where N = number of images, x/y are dimensions with only manual choices kept.
		% inputSignals
		% choices

	[inputImages, inputSignals, choices] = ciapkg.classification.signalSorter(inputImages,inputSignals,'passArgs', varargin);
end