function AlignItems(handles, type, varargin)
%ALIGNITEMS   Align Gui Items
%   ALIGNITEMS(HANDLES, OPTION, ...) aligns the gui items contained in the
%   handle vector HANDLES. The alignment method is controlled by OPTION.
%
%  ALIGNITEMS(HANDLES, OPTION)
%   If OPTIONS is 'left', 'right', 'top' or 'bottom', and no additional
%   argument is given, then all gui elements are aligned to the first
%   element of the array HANDLES.
%
%  ALIGNITEMS(HANDLES, OPTION, X)
%   If OPTIONS is 'left', 'right', 'top' or 'bottom', and an additional
%   argument X is given, then all elements are aligned to the parent so
%   that the distance from the parent's border is X.
%
%   If OPTIONS is 'row right', 'row up', 'row left' or 'row down', and an
%   additional argument X is given,  then the elements are aligned to a row
%   so that the distance between adjacent elements is specified by X. If X
%   is a scalar, then the distance is uniform, otherwise, the length of X
%   must be equal to the length of HANDLES minus one.
%
%  ALIGNITEMS(HANDLES, OPTION, FRAME, SEP, SIZE)
%   If OPTIONS is 'stretch left', 'stretch right', 'stretch top' or
%   'stretch bottom', the the elements are stretched to the specified
%   direction up to a distance FRAME from the parent's border. If HANDLES
%   is a vector, then the distance between adjacent gui elements will be
%   SEP, and the relative size of the gui elements will be controlled by
%   the vector SIZE. The default for SIZE is a uniform size vector.
%
% Example
%   f = figure;
%   g = uicontrol('style', 'pushbutton', 'string', 'First');
%   h = uicontrol('style', 'pushbutton', 'string', 'Second');
%   AlignItems(g, 'left', 10);
%   AlignItems(g, 'bottom', 10);
%   AlignItems([g h], 'left');
%   AlignItems([g h], 'row up', 2);
%
% See also UICONTROL

% Copyright (c) 2010-2014 Peter Fiala

if ~all(ishandle(handles))
    error('Some members of input h are not handles');
end

u = get(handles, 'Units');
if ~iscell(u)
    u = {u};
end
for i = 1 : length(handles)
    set(handles(i), 'Units', 'pixels');
end
up = get(get(handles(1), 'parent'), 'units');
set(get(handles(1), 'parent'), 'units', 'pixels');

p = get(handles, 'Position');
if iscell(p)
    p = cell2mat(p);
end

switch type
    case 'left'
        if nargin > 2
            p(:,1) = varargin{1};
        else
            p(:,1) = p(1,1);
        end
    case 'right'
        if nargin > 2
            pos = get(get(handles(1), 'Parent'), 'Position');
            p(:,1) = pos(3)-varargin{1}-p(3);
        else
            p(:,1) = p(1,1)+p(1,3)-p(:,3);
        end
    case 'bottom'
        if nargin > 2
            p(:,2) = varargin{1};
        else
            p(:,2) = p(1,2);
        end
    case 'top'
        if nargin > 2
            pos = get(get(handles(1), 'Parent'), 'Position');
            p(:,2) = pos(4)-varargin{1}-p(4);
        else
            p(:,2) = p(1,2)+p(1,4)-p(:,4);
        end
    case 'row up'
        vSep = varargin{1};
        p(2:end,2) = p(1,2)+cumsum(p(1:end-1,4)+vSep(:));
    case 'row down'
        vSep = varargin{1};
        p(2:end,2) = p(1,2)-cumsum(p(2:end,4)+vSep(:));
    case 'row right'
        hSep = varargin{1};
        p(2:end,1) = p(1,1)+cumsum(p(1:end-1,3)+hSep(:));
    case 'row left'
        hSep = varargin{1};
        p(2:end,1) = p(1,1)-cumsum(p(2:end,3)+hSep(:));
    case 'stretch right'
        frame = varargin{1};
        n = length(handles);
        if n > 1
            sep = varargin{2};
        else
            sep = 0;
        end
        if length(varargin) == 3
            ratio = varargin{3};
        else
            ratio = ones(n,1);
        end
        Pos = get(get(handles(1), 'Parent'), 'Position');
        p(:,3) = (Pos(3) - p(1,1) - frame - (n-1)*sep) / sum(ratio) * ratio;
        p(2:end,1) = p(1,1)+cumsum(p(1:end-1,3)+sep);
    case 'stretch left'
        frame = varargin{1};
        n = length(handles);
        if n > 1
            sep = varargin{2};
        else
            sep = 0;
        end
        if length(varargin) == 3
            ratio = varargin{3};
        else
            ratio = ones(n,1);
        end
        p(:,3) = (p(1,1)+p(1,3)- frame - (n-1)*sep) / sum(ratio) * ratio;
        p(:,1) = frame;
        p(2:end,1) = p(1,1)+cumsum(p(1:end-1,3)+sep);
    case 'stretch up'
        frame = varargin{1};
        n = length(handles);
        if n > 1
            sep = varargin{2};
        else
            sep = 0;
        end
        if length(varargin) == 3
            ratio = varargin{3};
        else
            ratio = ones(n,1);
        end
        Pos = get(get(handles(1), 'Parent'), 'Position');
        p(:,4) = (Pos(4) - p(1,2) - frame - (n-1)*sep) / sum(ratio) * ratio;
        p(2:end,2) = p(1,2)+cumsum(p(1:end-1,4)+sep);
    otherwise
        error('AlignItems:Param', 'Unknown alignment type: %s', type);
end

for i = 1 : length(handles)
    set(handles(i), 'Position', p(i,:));
    set(handles(i), 'Units', u{i});
end
set(get(handles(1), 'parent'), 'units', up);

end