function varargout=uistack(Handles,StackOpt,Step)
%UISTACK Restack objects.
%   UISTACK(H) visually raises the visual stacking order of the objects, H. 
%   UISTACK(H,STACKOPT) where STACKOPT is 'up','down','top','bottom'
%   UISTACK(H,STACKOPT,STEP) where STEP is the distance to move 'up' and 'down'
%   applies the stacking option to the handles specified by H. All
%   handles, H, must have the same parent.

%   Loren Dean
%   Copyright 1984-2002 The MathWorks, Inc. 
%   $Revision: 1.8.4.1 $ $Date: 2004/11/29 23:33:39 $ 

error(nargchk(0,1,nargout));
error(nargchk(1,3,nargin));
if ~all(ishandle(Handles)),
  error('Invalid Handles passed to UISTACK');
end
if nargin==1,
  StackOpt='up';
  Step=1;
end
if nargin==2,
  Step=1;
end
if Step<0
    Step = 0;
end

Parent=get(Handles,{'Parent'});
Parent=[Parent{:}];
UParent=unique(Parent);
if length(UParent)>1,
  error('All handles passed to UISTACK must have the same Parent.');
end

% do not check for mixed type ordering once one case is found
% (only one special currently exists)
checkMixedType = true;

% move objects one type by one type
Hrest = Handles;
while ~isempty(Hrest)
    
    % find handles of the same type
    SameType = Hrest(1);
    Type = get(Hrest(1),'type');

    % check if the objects being moved are of the type where 
    % different types of objects can be restack relative to each other 

    % get a vector of items being restack
    % that correspond to each other either by type or by a special case
    if (checkMixedType && isItemMixedType(Hrest(1)))
        for i=2:length(Hrest)
            if (isItemMixedType(Hrest(i)))
                SameType = [SameType;Hrest(i)];
            end
        end
        checkMixedType = false;
    else
        for i=2:length(Hrest)
            if (strcmp(Type,get(Hrest(i), 'type')))
                SameType = [SameType;Hrest(i)];
            end
        end
    end
    
    % keep the rest
    TypeLoc = find(ismember(Hrest,SameType));
    Hrest(TypeLoc) = [];
    
    % get appropriate children based on type
    Children = getAppropriateChildren(SameType);
    
    if (length(Children) > length(SameType))
    
        % change stack order
        NewOrder = getNewOrder(SameType, Children, StackOpt, Step);

        % update stack order
        % For figures, need to do something special
        if isequal(UParent,0),
            for lp=length(NewOrder):-1:1,
                if strcmp(get(NewOrder(lp),'Visible'),'on'),
                    figure(NewOrder(lp));
                end
            end
        else,
            AllChildren = allchild(UParent);
            AllChildren(find(ismember(AllChildren,NewOrder))) = NewOrder;
            set(UParent,'Children',AllChildren);
        end    
    end
    
end %while

if nargout,
    varargout{1}=allchild(UParent);
end


% --------------------------------------------------------------------
function NewOrder = getNewOrder(SameType, Children, StackOpt, Step)

NOUSE = -1;

Parent = get(SameType(1),'parent');
HandleLoc=find(ismember(Children,SameType));

switch StackOpt,
case 'up',
    NewOrder=[ones(Step,1).*NOUSE;Children];
    HandleLoc = HandleLoc + Step;
    for lp=1:length(SameType),
        Idx=HandleLoc(lp);
        NewOrder= [NewOrder(1:Idx-Step-1);NewOrder(Idx);NewOrder(Idx-Step:Idx-1);NewOrder(Idx+1:length(NewOrder))];
    end % for lp
    NewOrder(find(NewOrder == NOUSE)) = [];

case 'down',
    NewOrder=[Children;ones(Step,1).*NOUSE];
    for lp=length(SameType):-1:1,
        Idx=HandleLoc(lp);
        NewOrder = [NewOrder(1:Idx-1);NewOrder(Idx+1:Idx+Step);NewOrder(Idx);NewOrder(Idx+Step+1:length(NewOrder))];
    end % for lp
    NewOrder(find(NewOrder == NOUSE)) = [];

case 'top',
    % to preserve the child order instead of the input handle order, uncomment the following line
    % SameType = Children(HandleLoc);
    Children(HandleLoc)=[];  
    NewOrder=[SameType;Children];

case 'bottom',
    % to preserve the child order instead of the input handle order, uncomment the following line
    % SameType = Children(HandleLoc);
    Children(HandleLoc)=[];  
    NewOrder=[Children;SameType];    

otherwise,
    error('Invalid Stack option for UISTACK');      

end % switch

% --------------------------------------------------------------------
function Children = getAppropriateChildren(SameType)
Parent = get(SameType(1), 'parent');

% determine which children are of the same type or otherwise correspond to 
% items in the SameType vector
if (isItemMixedType(SameType(1)))
    Children = findobj(allchild(Parent), 'flat');
    selectChildren = [];
    for i=1:length(Children)
        if (isItemMixedType(Children(i)))
            selectChildren = [selectChildren;Children(i)];
        end
    end
    Children = selectChildren;
else
    Type = get(SameType(1), 'type');
    Children=findobj(allchild(Parent), 'flat', 'type', Type);
end

% --------------------------------------------------------------------
function mixType = isItemMixedType(Item)

mixType = false;
if (isa(handle(Item), 'uicontainer') ||...
    isa(handle(Item), 'axes'))
    mixType = true;
end