function varargout = filtview(varargin)
%FILTVIEW Filter Viewer.
%   This graphical tool allows you to examine the magnitude and phase
%   responses, group delay, zeros and poles, and impulse and step responses
%   of a digital filter.
%
%   Type 'sptool' to start the Signal Processing GUI Tool and access
%   the Filter Viewer.
%
%   See also SPTOOL, SIGBROWSE, FILTDES, SPECTVIEW.

%   Copyright (c) 1988-98 by The MathWorks, Inc.
%       $Revision: 1.1 $

% NOTE: ud.limits is set to the current X- Y-limits of the plot.  This is
% necessary because ruler.m uses ud.limits, and to avoid the rulers from
% dictating the XY limits of the plot we must keep the rulers inside the
% axes. ud.limits does not contain the largest X- Y-limits possible for
% that plot, as it might be the case in other clients that use ud.limits.

if nargin == 0,
    if isempty(findobj(0,'tag','sptool'))
        disp('Type ''sptool'' to start the Signal GUI.')
    else
        disp('To use the Filter Viewer, click on a filter in the ''Filters''')
        disp('column in the ''SPTool'', and then click on the ''View'' button.')
    end
    return
elseif ~isstr(varargin{1})
    fvinit(varargin{:})
    drawnow
    shh = get(0,'showhiddenhandles');
    set(0,'showhiddenhandles','on')
    ud = get(gcf,'userdata');

    set(ud.toolbar.zoomgroup,'visible','on')
    set(ud.toolbar.helpgroup,'visible','on')
    set(0,'showhiddenhandles',shh)
    return
end

action = varargin{1};

switch action
% ----------------------------------------------------------------------
% plotTitles = filtview('plotTitles',realFilterFlag)
%   
% Inputs:
%     realFilterFlag - flag indicating that filter being viewed is real
% Outputs:
%     plotTitles - list of plots available to focus on by rulers
%
case 'plotTitles'

    realFilterFlag = varargin{2};
    if realFilterFlag
        plotTitles ={'Magnitude','Phase','Group Delay',...
	        'Zeros and Poles','Impulse Response','Step Response',};
    else % Complex filter
        plotTitles ={'Magnitude','Phase','Group Delay',...
                'Zeros and Poles','Impulse (Real)',...
                'Impulse (Imag)','Step (Real)','Step (Imag)'};
    end
    varargout{1} = plotTitles;

%----------------------------------------------------------------------
% [FsStr filtLabelStr] = filtview('filtFsLabelStrs',ud.prefs,ud.ht,ud.filt)
%   Call local function to determine the correct strings for Fs and filter
%   label (the label which lists the names of the filters currently being
%   viewed).
%
case 'filtFsLabelStrs'

    [FsStr filtLabelStr] = ...
        filtFsLabelStrs(varargin{2},varargin{3},varargin{4});
    varargout{1} = FsStr;
    varargout{2} = filtLabelStr;

%----------------------------------------------------------------------
% [ud.lines] = filtview('emptyLinesStruct')
%  fvinit.m uses this case to access the local function emptyLineStruct.
%
case 'emptyLinesStruct'

    initializedLines = emptyLinesStruct;
    varargout{1} = initializedLines;
    
%----------------------------------------------------------------------
% [xlim1,xlim2,ylim1,ylim2] = filtview('zeropolePlotLims',ud.filt)
%   Call local function to alculate the limits for the zero-pole plot
%   (must keep the aspect ratio correct)
%
case 'zeropolePlotLims'

    filtStruct = varargin{2};
    [xlim1,xlim2,ylim1,ylim2] = zeropolePlotLims(filtStruct);
    
    varargout{1} = xlim1;
    varargout{2} = xlim2;
    varargout{3} = ylim1;
    varargout{4} = ylim2;

%----------------------------------------------------------------------
% filtview('cb',checkboxnum)
%   callback of checkbox to turn plots on/off
%
case 'cb'
    cbnum = varargin{2};
    fig = gcf;
    ud = get(fig,'userdata');
    ud.prefs.plots(cbnum) = 1-ud.prefs.plots(cbnum);
    set(fig,'userdata',ud)
    fvresize(1,fig)  % Add or remove axes and resize all other axes

    if ud.prefs.plots(cbnum)
        pflag = [0 0 0 0 0 0]';
        pflag(cbnum) = 1;
        filtview('plots',pflag)

        % Update the ud.limits of new plots as they're made visible
        ud = get(fig,'userdata');
        new_ud = filtview('setudlimits',ud,ud.ht.a,cbnum);
        set(fig,'userdata',new_ud)
        ud = get(fig,'userdata');
        
        if ud.prefs.tool.ruler  &  sum(ud.prefs.plots) == 1
            % Coming from a "no visible plots" state; make one plot visible
            ud.mainaxes = ud.ht.a(cbnum);
            ud.focusIndex = sptlegend('value',fig);
            [rulerPopupStr, rulerPopupVal] = ruler('getpopup',fig);

            % Account for the case where the filter was cleared
            % while viewing it in the filter viewer
            if isfield(ud,'filt.tf.num') 
                realFilterFlag = (isreal(ud.filt(ud.focusIndex).tf.num) &...
                    isreal(ud.filt(ud.focusIndex).tf.den));
            else
                realFilterFlag = 1;
            end
            
            if rulerPopupVal == 1  % Selection made via check box
                realDataFlag = 1;
            else                   % Selection made via ruler popup
                realDataFlag = (realFilterFlag | ~rem(rulerPopupVal,2));
            end
            ud.focusline = setFocusLine(ud.mainaxes,ud.lines,...
                cbnum,ud.focusIndex,realDataFlag);
            set(fig,'userdata',ud)
            rulerPopupVal = cbnum + (~realFilterFlag & (cbnum == 6));
            ruler('setpopup',fig,ud.prefs.plottitles,rulerPopupVal)
            ruler('newaxes',fig,cbnum,ud.mainaxes);    
            noTrackZeroPole(fig,ud)
        elseif ud.prefs.tool.ruler
            % Either, an invisible plot was selected via the ruler popup
            % OR, mainaxes limits changed because new plots were added
            plotIndex = find(ud.mainaxes == ud.ht.a);
            ruler('newlimits',fig,plotIndex,ud.focusline)
        end
    else     % If we're turning off a plot, zoom out of that plot
        fvzoom('zoomout',[zeros(1,cbnum-1) 1 zeros(1,6-cbnum)],fig)
        if ud.prefs.tool.ruler 
            if strcmp(get(ud.mainaxes,'visible'), 'off')
                if any(strcmp(get(ud.ht.a,'visible'),'on'))
                    % If other plots exist move rulers to the next plot.
                    [ud.mainaxes,ud.focusline,plotIndex,visPlots] = ...
                        setMainaxes(ud.mainaxes,ud.ht.a,ud.lines,1);
                    ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
                    set(fig,'userdata',ud)
                    ruler('newaxes',fig,plotIndex,ud.mainaxes)
                    noTrackZeroPole(fig,ud)
                else    % no visible plots
                    ud.focusline = [];
                    ud.focusIndex = [];
                    set(fig,'userdata',ud)
                    ruler('hidelines',fig,'all')
                    ruler('newsig',fig)          % sets the ruler values
                end
                ud = get(fig,'userdata');

                % Account for the case where the filter was cleared
                % while viewing it in the filter viewer
                if isfield(ud,'filt.tf.num')
                    realFilterFlag=(isreal(ud.filt(ud.focusIndex).tf.num)...
                        & isreal(ud.filt(ud.focusIndex).tf.den));
                else
                    realFilterFlag = 1;
                end
                
                updateRulrPopupList(fig,ud.prefs.plottitles,ud.ht.a,...
                    ud.mainaxes,realFilterFlag)
            else
                % Set ruler XY limits because subplots have been resized.
                plotIndex = find(ud.mainaxes == ud.ht.a);
                ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
                set(fig,'userdata',ud)
                ruler('newlimits',fig,plotIndex,ud.focusline)
            end
        end
    end

    % Disable and enable Magnitude and Phase popupmenus as appropriate
    if get(ud.ht.cb(1),'value') == 0
        set(ud.ht.magpop,'enable','off')
    else
        set(ud.ht.magpop,'enable','on')       
    end
    
    if get(ud.ht.cb(2),'value') == 0
        set(ud.ht.phasepop,'enable','off')
    else
        set(ud.ht.phasepop,'enable','on')       
    end
    
% ----------------------------------------------------------------------
% filtview('magpop')
%   callback of magnitude linear/log popup
%
case 'magpop'
    fig = gcf;
    ud = get(fig,'userdata');
    oldmode = ud.prefs.magmode;
    popupval = get(ud.ht.magpop,'value');
    popupstr = get(ud.ht.magpop,'string');
    if strcmp(oldmode,popupstr{popupval})
        return
    end

    switch popupval
    case 1
        ud.prefs.magmode = 'linear';
        set(ud.ht.a(1),'yscale','linear')
    case 2
        ud.prefs.magmode = 'log';
        set(ud.ht.a(1),'yscale','log')
     case 3
        ud.prefs.magmode = 'decibels';
        set(ud.ht.a(1),'yscale','linear')
    end
    set(fig,'userdata',ud)

    if ud.prefs.plots(1)
       filtview('plots',[1 0 0 0 0 0])
       fvzoom('zoomout',[1 0 0 0 0 0],fig)  % sets userdata
       ud = get(fig,'userdata');
       
       if ud.prefs.tool.ruler & (ud.ht.a(1) == ud.mainaxes)
           ruler('newsig',fig,1)           
           ruler('inbounds',fig,'ylim',1)  % make sure ruler limits are 
                                           % within the new axes limits
       end
    end
    
    p = sptool('getprefs','filtview1');
    p.magscale = popupval;
    sptool('setprefs','filtview1',p)
    
% ----------------------------------------------------------------------
% filtview('phasepop')
%   callback of phase degrees/radians popup
%
case 'phasepop'
    fig = gcf;
    ud = get(fig,'userdata');
    oldmode = ud.prefs.phasemode;
    popupval = get(ud.ht.phasepop,'value');
    popupstr = get(ud.ht.phasepop,'string');
    if strcmp(oldmode,popupstr{popupval})
        return
    end

    switch popupval
    case 1
        ud.prefs.phasemode = 'degrees';
        set(get(ud.ht.a(2),'title'),'string',ud.titles{2}{1})
    case 2
        ud.prefs.phasemode = 'radians';
        set(get(ud.ht.a(2),'title'),'string',ud.titles{2}{2})
    end
    set(fig,'userdata',ud)

    if ud.prefs.plots(2)
        filtview('plots',[0 1 0 0 0 0])
        fvzoom('zoomout',[0 1 0 0 0 0],fig) % sets userdata
        ud = get(fig,'userdata');
        
        if ud.prefs.tool.ruler & (ud.ht.a(2) == ud.mainaxes)
            ud = filtview('setudlimits',ud,ud.ht.a,2);
            set(fig,'userdata',ud)
            ruler('newlimits',fig,2,ud.focusline)
            ruler('newsig',fig,2)
            ud = get(fig,'userdata');
            ruler('inbounds',fig,'ylim',2) % make sure ruler limits are 
                                           % within the new axes limits
        end
    end

    p = sptool('getprefs','filtview1');
    p.phaseunits = popupval;
    sptool('setprefs','filtview1',p)

% ----------------------------------------------------------------------
% filtview('fscalepop')
%   callback of frequency scale linear/log popup
%    
case 'fscalepop'
    fig = gcf;
    ud = get(fig,'userdata');
    oldmode = ud.prefs.freqscale;    
    popupval = get(ud.ht.fscalepop,'value');
    popupstr = get(ud.ht.fscalepop,'string');
    if strcmp(oldmode,popupstr{popupval})
        return
    end
    
    switch popupval
    case 1
        ud.prefs.freqscale = 'linear';
        set(fig,'userdata',ud)
        set(ud.ht.a([1 2 3]),'xscale','linear')
        fvzoom('zoomout',[1 1 1 0 0 0],fig)

    case 2
        ud.prefs.freqscale = 'log';
        set(fig,'userdata',ud)

        if ud.prefs.freqrange == 3  % can't have negative frequencies
                                 % in logarithmic scale - change to [0..Fs/2]
            % so... change range!
            msgbox({'Sorry, you can''t have the Frequency Axis Scaling set'...
                'to logarithmic when the range includes negative frequencies.'...
                'Changing the range to positive frequencies only.'},...
                'Logarithmic Scaling Conflict','warn','modal')

            set(ud.ht.frangepop,'value',1)
            filtview('frangepop',fig)
            ud = get(fig,'userdata');
        end
        Fs = evalin('base',ud.prefs.Fs,'1');
        switch ud.prefs.freqrange
        case 1    % [0 Fs/2]
            flim = [Fs/ud.prefs.nfft Fs/2];
        case 2    % [0 Fs]
            flim = [Fs/ud.prefs.nfft Fs];
        end
        set(ud.ht.a([1 2 3]),'xscale','log','xlim',flim)
    end

    if ud.prefs.tool.ruler & any(ud.ht.a(1:3) == ud.mainaxes)
        plotIndex = find(ud.mainaxes == ud.ht.a);

        % Make sure that ud.limits matches new axes limits 
        ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
        set(fig,'userdata',ud)
        
        % Make sure that ruler values stay within the new axes limits
        ruler('inbounds',fig,'xlim',plotIndex)
        ud = get(fig,'userdata');
        
        ruler('newlimits',fig,plotIndex,ud.focusline)
        ruler('newsig',fig,plotIndex)
    end

    p = sptool('getprefs','filtview1');
    p.freqscale = get(ud.ht.fscalepop,'value');
    sptool('setprefs','filtview1',p)

% ----------------------------------------------------------------------
% filtview('frangepop',fig)
%   callback of frequency range popup
%
case 'frangepop'
    if nargin > 1
        fig = varargin{2};
    else
        fig = gcf;
    end

    ud = get(fig,'userdata');
    oldmode = ud.prefs.freqrange;
    popupval = get(ud.ht.frangepop,'value');
    popupstr = get(ud.ht.frangepop,'string');
    if (oldmode == popupval)
        return
    end
    switch popupval
    case 1
        ud.prefs.freqrange = 1;
    case 2
        ud.prefs.freqrange = 2;
    case 3
        % if in log scaling, don't allow display of negative frequencies
        if strcmp(ud.prefs.freqscale,'log')
            % so don't change range!
            msgbox({'Sorry, you can''t set the range to include negative' ...
                'frequencies when the Frequency Axis Scaling is logarithmic.'},...
                'Logarithmic Scaling Conflict','warn','modal')
            set(ud.ht.frangepop,'value',ud.prefs.freqrange)
            return
        end
        ud.prefs.freqrange = 3;
    end
    set(fig,'userdata',ud)
    
    filtview('plots',[ud.prefs.plots(1:3); 0; 0; 0],fig)
    fvzoom('zoomout',[ud.prefs.plots(1:3)' 0 0 0],fig) % sets userdata
    ud = get(fig,'userdata'); 
        
    % Make sure that rulers appear within the new axes limits
    if ud.prefs.tool.ruler & any(ud.ht.a(1:3) == ud.mainaxes)
        plotIndex = find(ud.mainaxes == ud.ht.a);
        ruler('inbounds',fig,'xlim',plotIndex) % make sure ruler limits are 
                                               % within the new axes limits
        if (ud.prefs.freqrange ~= oldmode)
            ruler('updatepeaksgroup',fig)
        end
    end

    p = sptool('getprefs','filtview1');
    p.freqrange = get(ud.ht.frangepop,'value');
    sptool('setprefs','filtview1',p)

% ----------------------------------------------------------------------
% filtview('Fs',fig)
%   callback of sampling frequency edit box 
%   (or you can use this to set the sampling frequency if you
%   set the string of ud.ht.Fsedit first)
%
case 'Fs'
    if nargin < 2
        fig = gcf;
    else
        fig = varargin{2};
    end

    ud = get(fig,'userdata');

    str = get(ud.ht.Fsedit,'string');

    if isequal(str,ud.prefs.Fs)
        return
    end

    [Fs,err] = validarg(str,[0 Inf],[1 1],'sampling frequency');
    if err
        set(ud.ht.Fsedit,'string',ud.prefs.Fs)
        return
    else
        ud.prefs.Fs = str;
        set(fig,'userdata',ud)
        if ~isempty(ud.tabfig)    % update settings figure
            data = get(ud.tabfig,'userdata');
            % this panel has been created since it is the first 1
            fvprefhand('populate',ud.tabfig,1,ud.prefs)
        end
        fvzoom('zoomout',ud.prefs.plots,fig)
        filtview('plots',ud.prefs.plots,fig)
    end
 
% ----------------------------------------------------------------------
% filtview('plots',plots,fig,need_update)
%   updates the plots indicated with a '1' in the plots vector
%   
case 'plots'
    if nargin < 3
        fig = gcf;
    else
        fig = varargin{3};
    end

    ud = get(fig,'userdata');

    if nargin < 4
        need_update = 1:length(ud.filt);   % everything needs updating
    else
        need_update = varargin{4};
    end
    
    plots = varargin{2};
    if all(plots==0)
        return
    end

    if isempty(ud.filt)
        % uninitialized tool - no filter
        % set axes limits to default value [0 1]
        for i=1:3
            if plots(i)
                set(ud.ht.a(i),'xlim',[0 1])
            end
        end
        return
    end
    
    maxFs = evalin('base',ud.prefs.Fs,'1');
    nfft = ud.prefs.nfft;
    
    if strcmp(ud.prefs.freqscale,'log')
        xlim1 = maxFs/ud.prefs.nfft;
    else
        xlim1 = 0;
    end
    switch ud.prefs.freqrange
    case 1    % [0 Fs/2]     
        flim = [xlim1 maxFs/2];
    case 2    % [0 Fs]      
        flim = [xlim1 maxFs];
    case 3    % [-Fs/2 Fs/2]
        flim = [-maxFs/2 maxFs/2];
    end

    % Loop through selected filters that need updating        
    for i = need_update
        Fs = ud.filt(i).Fs;
        switch ud.prefs.freqrange
        case 1    % [0 Fs/2]
            ud.filt(i).f = 0:Fs/nfft:(Fs/2 - Fs/(2*nfft));
        case 2    % [0 Fs]
            ud.filt(i).f = 0:Fs/nfft:(Fs - Fs/nfft);
        case 3    % [-Fs/2 Fs/2]
            ud.filt(i).f = fftshift(0:Fs/nfft:(Fs - Fs/nfft));
            ind = find(ud.filt(i).f>=Fs/2);
            ud.filt(i).f(ind) = ud.filt(i).f(ind)-Fs;
        end
    
        if any(plots([1 2 3]))
            ud.filt(i).H = fft(ud.filt(i).tf.num,nfft);
            warnsave = warning; 
            warning('off')   % prevent possible divide by 0 message
            ud.filt(i).H = ud.filt(i).H./fft(ud.filt(i).tf.den,nfft);
            warning(warnsave)
            switch ud.prefs.freqrange
            case 1    % [0 Fs/2]
                ud.filt(i).H = ud.filt(i).H(1:nfft/2);
            case 3    % [-Fs/2 Fs/2]
                ud.filt(i).H = fftshift(ud.filt(i).H);
            end
        end
        
        if isempty(ud.filt(i).lineinfo)
            lineColor = ud.colororder{1};
            lineStyle = ud.linestyleorder{1};
        else
            lineColor = ud.filt(i).lineinfo.color;
            lineStyle = ud.filt(i).lineinfo.linestyle;
        end
        
        if plots(1)
            if isempty(ud.lines(i).mag)
                ud.lines(i).mag = line(1,1,'tag','magline',...
                    'parent',ud.ht.a(1), ...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).mag,'color',lineColor,'linestyle',lineStyle)
            if strcmp(ud.prefs.magmode,'decibels')
                absH = abs(ud.filt(i).H);
                ind = find(absH>0);
                dbH = -Inf; dbH = dbH(ones(size(absH)));
                dbH(ind) = 20*log10(absH(ind));
                set(ud.lines(i).mag,'xdata',ud.filt(i).f,...
                    'ydata',dbH,'visible','on')
            else
                set(ud.lines(i).mag,'xdata',ud.filt(i).f,...
                    'ydata',abs(ud.filt(i).H),'visible','on')
            end        
        end
        
        if plots(2)
            if isempty(ud.lines(i).phase)
                ud.lines(i).phase = line(1,1,'tag','phaseline',...
                    'parent',ud.ht.a(2), ...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).phase,'color',lineColor,'linestyle',lineStyle)
            if ud.prefs.freqrange < 3
                pha = unwrap(angle(ud.filt(i).H));
            else
                pha_neg = unwrap(angle(ud.filt(i).H(nfft/2:-1:1)));
                pha_neg = pha_neg(end:-1:1);
                pha_pos = unwrap(angle(ud.filt(i).H((nfft/2+1):end)));
                pha = [pha_neg(:); pha_pos(:);];
            end

            switch ud.prefs.phasemode
            case 'degrees'
                set(ud.lines(i).phase,'xdata',ud.filt(i).f,...
                    'ydata',pha*180/pi,'visible','on')
            case 'radians'
                set(ud.lines(i).phase,'xdata',ud.filt(i).f,...
                    'ydata',pha,'visible','on')
            end
        end
        
        if plots(3)
            warnsave = warning; 
            warning('off');  % turn off divide by zero warning
            ud.filt(i).G = grpdelay(ud.filt(i).tf.num,ud.filt(i).tf.den,...
                           ud.filt(i).f,Fs);
            warning(warnsave);  
            if isempty(ud.lines(i).grpdelay)
                ud.lines(i).grpdelay = line(1,1,'tag','delayline',...
                    'parent',ud.ht.a(3), ... 
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).grpdelay,'color',lineColor,'linestyle',lineStyle)
            set(ud.lines(i).grpdelay,'xdata',ud.filt(i).f,...
                'ydata',ud.filt(i).G,'visible','on')
        end
     
        if plots(4)
            if isempty(ud.lines(i).z)               
                ud.lines(i).z = line(NaN,NaN,'tag','zerosline',...
                    'linestyle','none','marker','o',...
                    'parent',ud.ht.a(4),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).z,'color',lineColor)
            if isempty(ud.lines(i).p)
                ud.lines(i).p = line(NaN,NaN,'tag','polesline',...
                    'linestyle','none','marker','x',...
                    'parent',ud.ht.a(4),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).p,'color',lineColor)
            if isempty(ud.filt(i).zpk)
                if ~isempty(ud.filt(i).ss)
                    [z,p,k] = ss2zp(ud.filt(i).ss.a,ud.filt(i).ss.b,...
                        ud.filt(i).ss.c,ud.filt(i).ss.d,1);
                elseif ~isempty(ud.filt(i).sos)
                    [z,p,k] = sos2zp(ud.filt(i).sos);
                else
                    if length(ud.filt(i).tf.den)<length(ud.filt(i).tf.num)
                        den = ud.filt(i).tf.den;
                        den(length(ud.filt(i).tf.num)) = 0;   % zero pad
                        [z,p,k] = tf2zp(ud.filt(i).tf.num,den);
                    else
                        [z,p,k] = tf2zp(ud.filt(i).tf.num,ud.filt(i).tf.den);
                    end
                end
                ud.filt(i).zpk.z = z;
                ud.filt(i).zpk.p = p; 
                ud.filt(i).zpk.k = k;
            end
            set(ud.lines(i).z,'xdata',real(ud.filt(i).zpk.z),...
                'ydata',imag(ud.filt(i).zpk.z),'visible','on')
            set(ud.lines(i).p,'xdata',real(ud.filt(i).zpk.p),...
                'ydata',imag(ud.filt(i).zpk.p),'visible','on')
            set(ud.ht.a(4),'ylimmode','auto','xlimmode','auto')
            apos = get(ud.ht.a(4),'Position');
            set(ud.ht.a(4),'DataAspectRatio',[1 1 1],...
                'PlotBoxAspectRatio',apos([3 4 4]))
        end
        if any(plots([5 6]))
            [ud.filt(i).imp,ud.filt(i).t] = ...
                impz(ud.filt(i).tf.num,ud.filt(i).tf.den,ud.prefs.nimp,Fs);
        end
        if plots(5)
            if isempty(ud.lines(i).imp)
                ud.lines(i).imp = line(nan,nan,'tag','implinedots',...
                    'linestyle','none','marker','o',...
                    'parent',ud.ht.a(5),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).imp,'color',lineColor,'markerfacecolor',lineColor)
            if isempty(ud.lines(i).impstem)
                ud.lines(i).impstem = line(nan,nan,'color',lineColor,...
                    'linestyle','-',...
                    'tag','implinestem',...
                    'parent',ud.ht.a(5),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).impstem,'color',lineColor,'linestyle',lineStyle)
            if isempty(ud.lines(i).impc)
                ud.lines(i).impc = line(nan,nan,'tag','implinedotsc',...
                    'linestyle','none','marker','*',...
                    'parent',ud.ht.a(5),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).impc,'color',lineColor,'markerfacecolor',lineColor)
            if isempty(ud.lines(i).impstemc)
                ud.lines(i).impstemc = line(nan,nan,'tag','implinestemc',...
                    'linestyle','-',...
                    'parent',ud.ht.a(5),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).impstemc,'color',lineColor,'linestyle',lineStyle)
            setstem([ud.lines(i).imp ud.lines(i).impstem],ud.filt(i).t,...
                    real(ud.filt(i).imp))
            if sum(imag(ud.filt(i).imp).^2) > 1e-10*sum(real(ud.filt(i).imp).^2)
                setstem([ud.lines(i).impc ud.lines(i).impstemc],ud.filt(i).t,...
                        imag(ud.filt(i).imp))
                set([ud.lines(i).impc ud.lines(i).impstemc],'visible','on')
            else
                set([ud.lines(i).impc ud.lines(i).impstemc],'visible','off')
            end
            set([ud.lines(i).imp ud.lines(i).impstem],'visible','on')
        end
        
        if plots(6)
            if isempty(ud.lines(i).step)
                ud.lines(i).step = line(nan,nan,'tag','steplinedots',...
                    'linestyle','none','marker','o',...
                    'parent',ud.ht.a(6),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).step,'color',lineColor,'markerfacecolor',lineColor)
            if isempty(ud.lines(i).stepstem)
                ud.lines(i).stepstem = line(nan,nan,'tag','steplinestem',...
                    'linestyle','-',...
                    'parent',ud.ht.a(6),...
                    'buttondownfcn','filtview(''mdown'')');
            end  
            set(ud.lines(i).stepstem,'color',lineColor,'linestyle',lineStyle)
            if isempty(ud.lines(i).stepc)
                ud.lines(i).stepc = line(nan,nan,'tag','steplinedotsc',...
                    'linestyle','none','marker','*',...
                    'parent',ud.ht.a(6),...
                    'buttondownfcn','filtview(''mdown'')');
            end
            set(ud.lines(i).stepc,'color',lineColor,'markerfacecolor',lineColor)
            if isempty(ud.lines(i).stepstemc)
                ud.lines(i).stepstemc = line(nan,nan,'tag','steplinestemc',...
                    'linestyle','-',...
                    'parent',ud.ht.a(6),...
                    'buttondownfcn','filtview(''mdown'')');
            end 
            set(ud.lines(i).stepstemc,'color',lineColor,'linestyle',lineStyle)
            ud.filt(i).step = filter(ud.filt(i).tf.num,ud.filt(i).tf.den,...
                ones(1,length(ud.filt(i).t)));
            setstem([ud.lines(i).step ud.lines(i).stepstem],ud.filt(i).t,...
                real(ud.filt(i).step))
            if sum(imag(ud.filt(i).step).^2) > 1e-10*sum(real(ud.filt(i).step).^2)
                setstem([ud.lines(i).stepc ...
                        ud.lines(i).stepstemc],ud.filt(i).t,...
                        imag(ud.filt(i).step))
                set([ud.lines(i).stepc ud.lines(i).stepstemc],'visible','on')
            else
                set([ud.lines(i).stepc ud.lines(i).stepstemc],'visible','off')
            end
            set([ud.lines(i).step ud.lines(i).stepstem],'visible','on')
            set(ud.ht.a(6),'ylimmode','auto',...
                'xlim',[ud.filt(i).t(1)-1/Fs  ud.filt(i).t(end)+1/Fs])
            
        end
         
        set(fig,'userdata',ud)
        sptool('import',ud.filt(i))
    end % looping trough selected filters
    
    % set all axes properties only once:
    if plots(1)
        % Make sure that proper scale is used for magnitude axis
        if get(ud.ht.magpop,'value') == 2
            set(ud.ht.a(1),'yscale','log')
        else
            set(ud.ht.a(1),'yscale','linear')        
        end
        set(ud.ht.a(1),'ylimmode','auto','xlim',flim)
    end
    
    if plots(2), set(ud.ht.a(2),'ylimmode','auto','xlim',flim), end
    if plots(3)  % set ylims of group delay plot
        gd_ylim = filtview('gd_ylim',ud.filt);
        set(ud.ht.a(3),'ylim',gd_ylim)
        set(ud.ht.a(3),'xlim',flim)
    end
    %if plots(3), set(ud.ht.a(3),'ylimmode','auto','xlim',flim), end

    if any(plots(1:3))  % Make sure that proper scale is used for freq axis
        if get(ud.ht.fscalepop,'value') == 2
            set(ud.ht.a(find(plots(1:3))),'xscale','log')
        else
            set(ud.ht.a(find(plots(1:3))),'xscale','linear')        
        end
    end
    
    if plots(4)
        [xlim1,xlim2,ylim1,ylim2] = zeropolePlotLims(ud.filt);
        set(get(ud.ht.a(4),'xlabel'),'userdata',[xlim1 xlim2 ylim1 ylim2]);
    end

    if any(plots([5 6]))
        tmax = -inf;
        for i = 1:length(ud.filt)
            tmax = max([tmax; ud.filt(i).t(end)]);
        end
        
        xlim = [-1/maxFs tmax+1/maxFs];
        if plots(5),set(ud.ht.a(5),'ylimmode','auto','xlim',xlim), end
        if plots(6),set(ud.ht.a(6),'ylimmode','auto','xlim',xlim), end
    end

%------------------------------------------------------------------------
%   gd_ylim = filtview('gd_ylim',filt)
%      compute ylimits for group delay plot
%      assumes .H and .G fields of filt struct are set correctly
case 'gd_ylim' 
    filt = varargin{2};
    if length(filt)==0
        gd_ylim = [0 1];
    else
        gd_ylim = [Inf -Inf];
    end
    for i=1:length(filt)
        ind = find( abs(filt(i).H) > (max(abs(filt(i).H))*1e-10) );
        gd_ylim = [min(gd_ylim(1),min(filt(i).G(ind))-1) ...
                 max(gd_ylim(2),max(filt(i).G(ind))+1)]; 
    end
    varargout{1} = gd_ylim;
    
%------------------------------------------------------------------------
% filtview('changefocus')
%  callback of sptlegend
%
case 'changefocus'
    
    newfocusIndex = sptlegend('value');
    fig = gcbf;
    ud = get(fig,'userdata');
    plotIndex = find(ud.mainaxes == ud.ht.a);

    realFilterFlag = (isreal(ud.filt(newfocusIndex).tf.num) &...
        isreal(ud.filt(newfocusIndex).tf.den));

    % Make sure that ruler popup is updated correctly when changing from a
    % real filter to a complex filter and vice versa.
    if ud.prefs.tool.ruler & ~isempty(ud.filt)
        currentPopupVal = get(ud.ruler.hand.rulerpopup,'value');   
        newPlottitles = filtview('plotTitles',realFilterFlag);
        newPopupVal = cmplxFiltPopupVal(currentPopupVal,newPlottitles,...
                                                       ud.prefs.plottitles);
        ud.prefs.plottitles = newPlottitles;
        set(fig,'userdata',ud)
        updateRulrPopupList(fig,newPlottitles,ud.ht.a,...
                                      ud.mainaxes,realFilterFlag)
        str = ruler('getpopup',fig);
        ruler('setpopup',fig,str,newPopupVal)
    end
        
    if isempty(ud.focusIndex) 
        h = [];
    else
        hstepc = ud.lines(ud.focusIndex).stepc;
        himpc = ud.lines(ud.focusIndex).impc;
        h = [hstepc himpc];
    end
    if  isempty(ud.focusline) | isempty(h) | realFilterFlag | ...
            all(ud.focusline~=h)
        realDataFlag = 1;   % data is real
    else    
        realDataFlag = 0;   % data is complex
    end

    ud.focusline = setFocusLine(ud.mainaxes,ud.lines,...
                                plotIndex,newfocusIndex,realDataFlag);
    ud.focusIndex = newfocusIndex;
    set(fig,'userdata',ud)
    
    if ud.prefs.tool.ruler
        ruler('newsig',fig,plotIndex)
    end
    if isempty(find(ud.prefs.plots)) & ~isempty(ud.filt)
        sptlegend('setvalue',ud.legend.legendline,...
            ud.focusIndex,1,fig)
        set(ud.legend.legendline,'color',...
            ud.filt(ud.focusIndex).lineinfo.color)
    else
        sptlegend('setvalue',ud.focusline,ud.focusIndex,1,fig)
    end
    set(ud.legend.legendline,'linestyle', ...
                               ud.filt(ud.focusIndex).lineinfo.linestyle)
    bringToFront(fig,ud.focusIndex)
    
%------------------------------------------------------------------------
% filtview('newColor',lineColor,lineStyle)
%  newColorCallback of sptlegend
%  color and linestyle of ud.focusline have already been updated
%
case 'newColor'
    lineColor = varargin{2};
    lineStyle = varargin{3};
    
    fig = gcf;
    ud = get(fig,'userdata');
    
    indx = ud.focusIndex;
    if isempty(indx)
        indx = get(ud.legend.legendpopup,'value');
    end
    ud.filt(indx).lineinfo.color = lineColor;
    ud.filt(indx).lineinfo.linestyle = lineStyle;
 
    set(fig,'userdata',ud)
    
    % poke back into SPTool
    sptool('import',ud.filt(indx))

    % Only change the line style of lines, not markers; in other words
    % don't change the line style of circles, dots or asterisks.
    flds = {'mag'
            'phase'
            'grpdelay'
            'impstem'
            'impstemc'
            'stepstem'
            'stepstemc'};

    for i = 1:length(flds)
        lineHandle = eval(['ud.lines(', num2str(indx),  ').', flds{i}]);
        if ishandle(lineHandle)
            set(lineHandle,'linestyle',lineStyle)
        end
    end

    h = [ud.lines(indx).imp ud.lines(indx).imp  ud.lines(indx).step ...
            ud.lines(indx).stepc];
    set(h,'markerfacecolor',lineColor)
    handleCell = struct2cell(ud.lines(indx));
    h = [handleCell{:}];
    set(h,'color',lineColor)
    
%------------------------------------------------------------------------
% filtview('rulerpopup')
%   callback of the ruler popupmenu
%
case 'rulerpopup'
    fig = gcf;
    ud = get(fig,'userdata');
    [rulerPopupStr,rulerPopupVal] = ruler('getpopup',fig);
    realFilterFlag = length(rulerPopupStr) <= 7;
    none_indx = strcmp(rulerPopupStr{1},'<none>');

    if none_indx & (rulerPopupVal == 1)
        return
    end

    plotIndex = rulerPopupVal - none_indx;
    plotIndex = plotIndex - (~realFilterFlag &  ((plotIndex==6) | ...
        (plotIndex==7))) - 2*(~realFilterFlag & plotIndex>=8);
        
    if plotIndex == find(ud.mainaxes == ud.ht.a) & ...
            strcmp(get(ud.mainaxes,'visible'),'on')
        realDataFlag = (realFilterFlag | rem(rulerPopupVal-none_indx,2));
        focusline = setFocusLine(ud.mainaxes,ud.lines,...
            plotIndex,ud.focusIndex,realDataFlag);
        if isequal(ud.focusline,focusline)
            return
        end
    end
        
    if ~ud.prefs.plots(plotIndex)               % plot is not selected
        set(ud.ht.cb(plotIndex),'value',1);     % select checkbox
        filtview('cb',plotIndex)                % display plot 
        if ~realFilterFlag & any((rulerPopupVal-none_indx)==[6 8])
            if none_indx, rulerPopupStr = rulerPopupStr(2:end); end
            ruler('setpopup',fig,rulerPopupStr,rulerPopupVal-none_indx)
        end
        ud = get(fig,'userdata');
    end
    
    complxFlag = ~realFilterFlag & (any((rulerPopupVal-none_indx)==[6 8]));
    ud.mainaxes = ud.ht.a(plotIndex);
    ud.focusline = setFocusLine(ud.mainaxes,ud.lines,plotIndex,...
        ud.focusIndex,~complxFlag);
        
    ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
    set(fig,'userdata',ud)
    ruler('newaxes',fig,plotIndex,ud.mainaxes)
    noTrackZeroPole(fig,ud)                

%------------------------------------------------------------------------
% ud = filtview('setudlimits',ud,axesList,axesIndexes)
% Inputs:
%   ud - structure containing client's userdata
%   axesList - list of handles of the axes of all subplots
%   axesIndexes - indicies of the handles of all visible subplots
% Ouputs:
%   ud - structure containing client's modified userdata (new xlim and
%        ylim)
%
case 'setudlimits'

    ud = varargin{2};
    axesList = varargin{3};
    axesIndexes = varargin{4};

    for i = 1:length(axesIndexes)
        ud.limits(axesIndexes(i)).xlim=get(axesList(axesIndexes(i)),'xlim');
        ud.limits(axesIndexes(i)).ylim=get(axesList(axesIndexes(i)),'ylim');
    end
    
    varargout{1} = ud;

%------------------------------------------------------------------------
% filtview('settab')
%  open settings tabbed dialog box
%
case 'settab'
    fig = gcf;
    ud = get(fig,'userdata');

    if ud.pointer == 2  % help mode
        fvhelp('settab')
        return
    end

    if isempty(ud.tabfig)
        setptr(fig,'watch');
        ud.pointer = -1; 
        set(fig,'userdata',ud)
        tabfig1 = tabfig(0,'fvprefhand',ud.sz);
        ud.tabfig = tabfig1;
        ud.pointer = 0; 
        set(fig,'userdata',ud);
        fvmotion(ud.toolnum)
    else
        set(ud.tabfig,'visible','on')
        figure(ud.tabfig)
    end
    
%------------------------------------------------------------------------
% filtview('mdown')
%  mouse down event on one of the lines
%
case 'mdown'
    [l,fig] = gcbo;
    ud = get(fig,'userdata');
    oldFocusIndx = ud.focusIndex;
    
    if ud.pointer == 2  % help mode
        fvhelp('line')
        return
    end
    
    if ~justzoom(fig)
        ax = get(l,'parent');
        if ax==ud.ht.a(5) | ax==ud.ht.a(6)
            erasemode = 'xor';
        else
            erasemode = 'background';
        end
        
        xlim = get(ax,'xlim');
        ylim = get(ax,'ylim');
    
        % Determine which line from which filter was selected
        for i = 1:length(ud.lines)
            allLines = struct2cell(ud.lines(i));
            allLines = [allLines{:}];
            if any(allLines==l)
                ud.focusIndex = i;
                break
            end
        end
        set(fig,'userdata',ud)
        
        % Setting XY limits here causes redrawing of the plot when you
        % click on the line - try to avoid this in the future
        set(ax,'ylimmode','auto','xlimmode','auto')
        bounds.xlim = get(ax,'xlim');
        bounds.ylim = get(ax,'ylim');
        set(ax,'ylim',ylim,'xlim',xlim)
            
        if ud.prefs.tool.ruler & (ax == ud.mainaxes)
            invis = [ud.ruler.lines ud.ruler.markers];
        else
            invis = [];
        end

        limchange = panfcn('erasemode',erasemode,'bounds',bounds,...
            'invisible',invis,'immediate',0);

        plotIndex = find(ax == ud.ht.a);
        if limchange
            ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
            set(fig,'userdata',ud);
        end

        if ud.prefs.tool.ruler & (ax == ud.mainaxes) & ...
                (oldFocusIndx==ud.focusIndex) & flisequal(fig,ud.focusline,l)
            % just dragging the line (where rulers are focused) around
            ruler('newlimits',fig,plotIndex)
            ruler('showlines',fig)
        elseif ud.prefs.tool.ruler % Move rulers to new line
            % Line chosen in new axes, hence, make new axes the mainaxes
            if (ax ~= ud.mainaxes)  
                ud.mainaxes = ax;
                set(fig,'userdata',ud)
            end
            ud = get(fig,'userdata');

            realFilterFlag = (isreal(ud.filt(ud.focusIndex).tf.num) &...
                              isreal(ud.filt(ud.focusIndex).tf.den));
            rulerPopVal = plotIndex;

            % Make sure that ruler popup is updated correctly when changing
            % from a real filter to a complex filter and vice versa.
            realDataFlag = realdataFlag(l,ud.lines,ud.focusIndex);
            if ~realFilterFlag
                if realDataFlag        % the real part was chosen
                    if (plotIndex == 6)   
                        rulerPopVal = plotIndex + 1;
                    end
                else                   % the imaginary part was chosen
                    switch plotIndex
                    case 5, rulerPopVal = 6;
                    case 6, rulerPopVal = 8;
                    end
                end
            end

            % Don't set the string of the ruler popup if it hasn't changed;
            % in case we're viewing only real or complex filters
            oldRealFilterFlag = (isreal(ud.filt(oldFocusIndx).tf.num) &...
                              isreal(ud.filt(oldFocusIndx).tf.den));
            if (oldRealFilterFlag ~= realFilterFlag)
                newPlottitles = filtview('plotTitles',realFilterFlag);
                updateRulrPopupList(fig,newPlottitles,ud.ht.a,...
                    ud.mainaxes,realFilterFlag)
            end
            str = ruler('getpopup',fig);
            ruler('setpopup',fig,str,rulerPopVal)

            
            ud.focusline = setFocusLine(ud.mainaxes,ud.lines,...
                                   plotIndex,ud.focusIndex,realDataFlag);
            set(fig,'userdata',ud)
            ud = get(fig,'userdata');
            ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
            set(fig,'userdata',ud)
            ruler('newaxes',fig,plotIndex,ud.mainaxes)
            noTrackZeroPole(fig,ud)
        else        
            realDataFlag = realdataFlag(l,ud.lines,ud.focusIndex);
            plotIndex = find(ax == ud.ht.a);
            ud.focusline = setFocusLine(ud.mainaxes,ud.lines,...
                plotIndex,ud.focusIndex,realDataFlag);
            set(fig,'userdata',ud)
        end
        if ax == ud.ht.a(4) & limchange
            xlim = get(ud.ht.a(4),'xlim');
            ylim = get(ud.ht.a(4),'ylim');
            set(get(ud.ht.a(4),'xlabel'),'userdata',[xlim ylim]);
        end
    end
    ud = get(fig,'userdata');
    bringToFront(fig,ud.focusIndex)
    sptlegend('setvalue',ud.focusline,ud.focusIndex,1,fig)
    set(ud.legend.legendline,'linestyle', ...
        ud.filt(ud.focusIndex).lineinfo.linestyle)
    
%------------------------------------------------------------------------
% enable = filtview('selection',action,msg,SPTfig)
%  respond to selection change in SPTool
% possible actions are
%    'view'
%  Button is enabled when
%     a) there is a filter selected
%
case 'selection'
    msg = varargin{3};
    SPTfig = varargin{4};
    fig = findobj('type','figure','tag','filtview');
    
    % get all filters (f) and the indexes (ind) of the selected filters
    [f,ind] = sptool('Filters',1,SPTfig);

    if isempty(f(ind))
        varargout{1} = 'off';
    else
        varargout{1} = 'on';
    end

    if ~isempty(fig)  % update filter viewer
        ud = get(fig,'userdata');
        switch msg
        case 'label'
            if ~isempty(ud.filt)
                oldFiltLabels = {ud.filt.label};
                newFiltLabels = {f(ind).label};
                % make sure FILTER (not signal or spectrum) has changed
                % its label
                if ~isequal(oldFiltLabels,newFiltLabels)
                    sptlegend('setstring',newFiltLabels,{},fig,1)
                    for i=1:length(ud.filt)
                        ud.filt(i).label = f(ind(i)).label;
                    end
                    set(fig,'userdata',ud)
                    [FsStr filtLabelStr] = filtFsLabelStrs(ud.prefs,ud.ht,ud.filt);
                    set(ud.ht.filterLabel,'string',filtLabelStr)
                end
            end
            return 
        case 'Fs'
            if any([ud.filt.Fs] ~= [f(ind).Fs])   % Filter's Fs has changed
                filtIndx = find([ud.filt.Fs] ~= [f(ind).Fs]);
                oldFs = ud.filt(filtIndx).Fs;
                newFs = f(ind(filtIndx)).Fs;
                ud.filt(filtIndx).Fs = newFs;
                ud.filt(filtIndx).f = ud.filt(filtIndx).f*(newFs/oldFs); 
                ud.filt(filtIndx).t = ud.filt(filtIndx).t/(newFs/oldFs);
               
                oldMaxFs = ud.prefs.Fs;
                newMaxFs = sprintf('%.9g',max([f(ind).Fs]));
             
                if ~strcmp(newMaxFs, oldMaxFs)  
                    ud.prefs.Fs = newMaxFs;
                    [FsStr filtLabelStr]=filtFsLabelStrs(ud.prefs,ud.ht,ud.filt);
                    set(ud.ht.Fsedit,'string',FsStr)

                    axesScale = str2double(newMaxFs)/str2double(oldMaxFs);
                    for i = 1:3
                        oldXlim = get(ud.ht.a(i),'xlim');
                        set(ud.ht.a(i),'xlim',oldXlim*axesScale)
                    end
                    for i = 5:6
                        oldXlim = get(ud.ht.a(i),'xlim');
                        set(ud.ht.a(i),'xlim',oldXlim/axesScale)
                    end
                end
                set(fig,'userdata',ud)
                
                h = struct2cell(ud.lines(filtIndx)); % Handles to lines
                h = [h{:}];
                for i = 1:3
                    hi = findobj(h,'parent',ud.ht.a(i));
                    for j = 1:length(hi)
                        set(hi(j),'xdata',get(hi(j),'xdata')*newFs/oldFs)
                    end
                end
                for i = 5:6
                    hi = findobj(h,'parent',ud.ht.a(i));
                    for j = 1:length(hi)
                        set(hi(j),'xdata',get(hi(j),'xdata')*oldFs/newFs)
                    end
                end
               
                if (filtIndx == ud.focusIndex) | ~strcmp(newMaxFs,oldMaxFs)  
                    % If on mainaxes fix ruler position
                    plotIndex = find(ud.mainaxes == ud.ht.a);
                    ruler('newlimits',fig,plotIndex)
                    ruler('newsig',fig,plotIndex)
                end
                return
            end    % Filter's Fs has changed
        end

        if ~isequal(f(ind),ud.filt)
            need_update = 1:length(ind);
            if isempty(ind)     % No filters in SPTool
                set(ud.ht.Fsedit,'string','')
                set(ud.ht.filterLabel,'string',['Filter: <none>'])
                ud.filt = [];
                for n = 1:length(ud.lines)
                    h = struct2cell(ud.lines(n));
                    h = [h{:}];
                    delete(h)
                end
                ud.lines = [];
                
                if ud.prefs.tool.ruler
                    ud.focusline = [];
                    ud.focusIndex = [];
                    set(fig,'userdata',ud)
                    ruler('newsig',fig)      % sets the ruler values
                    ud = get(fig,'userdata');
                end
            else  % New filter selected/created
                if ~isempty(ud.filt) 
                    % Find filters which need freq. response computed
                    % (don't include filters that were previously selected
                    % whose freq. response haven't changed)
                    newFiltSelection = f(ind);
                    [need_update,ud.lines,ud.focusIndex] = ...
                        redundantFilters(newFiltSelection,ud.filt,...
                        ud.lines,ud.focusIndex);
                else 
                    % Selecting a filter after un-selecting all filters
                    ud.lines = emptyLinesStruct;
                    ud.lines(length(f(ind))) = ud.lines(1);
                    ud.focusIndex = 1;
                end
                ud.filt = f(ind);
                plotIndex = find(ud.mainaxes == ud.ht.a);
                
                ud.prefs.Fs = sprintf('%.9g',max([f(ind).Fs]));
                [FsStr filtLabelStr] = filtFsLabelStrs(ud.prefs,ud.ht,ud.filt);
                set(ud.ht.filterLabel,'string',filtLabelStr)
                set(ud.ht.Fsedit,'string',FsStr) 
                
                for i=1:length(ud.filt) % Loop through the selected filters
                    % delete complex imp/step lines if filter is real, in case
                    % we are changing from a complex to a real filter
                    realFilterFlag = (isreal(ud.filt(i).tf.num) & ...
                        isreal(ud.filt(i).tf.den));
                    if realFilterFlag 
                        if ~isempty(ud.lines(i).impc)
                            delete([ud.lines(i).impc ud.lines(i).impstemc])
                            ud.lines(i).impc = [];
                            ud.lines(i).impstemc = [];
                        end
                        if ~isempty(ud.lines(i).stepc)
                            delete([ud.lines(i).stepc ud.lines(i).stepstemc])
                            ud.lines(i).stepc = [];
                            ud.lines(i).stepstemc = [];
                        end
                    end
                end  % looping through selected filters
            
            end      % new filter(s) selected/created
            set(fig,'userdata',ud)

            % Make sure that ruler popup is updated correctly when changing
            % from a real filter to a complex filter and vice versa.
            if ud.prefs.tool.ruler & ~isempty(ud.filt(ud.focusIndex)) 
                realFilterFlag = (isreal(ud.filt(ud.focusIndex).tf.num) &...
                              isreal(ud.filt(ud.focusIndex).tf.den));
                currentPopupVal = get(ud.ruler.hand.rulerpopup,'value');
                newPlottitles = filtview('plotTitles',realFilterFlag);
                newPopupVal = cmplxFiltPopupVal(currentPopupVal, ...
                                          newPlottitles, ud.prefs.plottitles);
                ud.prefs.plottitles = newPlottitles;
                set(fig,'userdata',ud)
                updateRulrPopupList(fig,newPlottitles,ud.ht.a,...
                                    ud.mainaxes,realFilterFlag)
                str = ruler('getpopup',fig);
                ruler('setpopup',fig,str,newPopupVal)
            end
            
            % Set line color and style for each new filter selected
            ud = get(fig,'userdata');
            for i = 1:length(ud.filt)     % loop through selected filters
                if isempty(ud.filt(i).lineinfo)
                    % assign next available line color and style
                    [ud.filt(i).lineinfo,ud.colorCount] = ...
                        nextcolor(ud.colororder,ud.linestyleorder, ...
                        ud.colorCount);
                    % poke back into SPTool
                    if nargin > 3
                        sptool('import',ud.filt(i),0,varargin{4})
                    else
                        sptool('import',ud.filt(i))
                    end
                
                end   % if-empty lineinfo
            end   % loop through selected filters
            set(fig,'userdata',ud);
            
            % Don't allow rulers to affect maximum axes limits computations
            if ud.prefs.tool.ruler, ruler('hidelines',fig,'all'), end
            filtview('plots',ud.prefs.plots,fig,need_update)
            
            ud = get(fig,'userdata');
            bringToFront(fig,ud.focusIndex)

            % New filter. Set the focusline correctly so that the rulers
            % will be set on appropriate subplot and focus on
            % correct line - if rulers were on imaginary line of complex
            % filter and new filter is also complex, focus rulers on the 
            % imaginary line of new filter.
            if ~isempty(f(ind)) 
                plotIndex = find(ud.mainaxes==ud.ht.a);
                ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
                realFilterFlag = (isreal(ud.filt(ud.focusIndex).tf.num) &...
                    isreal(ud.filt(ud.focusIndex).tf.den));

                if isempty(ud.focusIndex) 
                    h = [];
                else
                    hstepc = ud.lines(ud.focusIndex).stepc;
                    himpc = ud.lines(ud.focusIndex).impc;
                    h = [hstepc himpc];
                end
                if isempty(ud.focusline) | isempty(h) | realFilterFlag | ...
                        all(ud.focusline~=h)
                    realDataFlag = 1;   % data is real
                else    
                    realDataFlag = 0;   % data is complex
                end
                
                ud.focusline = setFocusLine(ud.mainaxes,ud.lines,...
                    plotIndex, ud.focusIndex,realDataFlag);
                set(fig,'userdata',ud)
                if ud.prefs.tool.ruler
                    ruler('newlimits',fig,plotIndex)
                    ruler('newsig',fig,plotIndex)
                    ruler('showlines',fig,ud.focusline)
                end
            end

            ud = get(fig,'userdata');
            
            if isempty(ind)     % No filters in SPTool
                sptlegend('setstring',{ },{},fig,0)
            else
                sptlegend('setstring',{ud.filt.label},{},fig,0)
                if isempty(find(ud.prefs.plots)) & ~isempty(ud.filt)
                    sptlegend('setvalue',ud.legend.legendline,...
                        ud.focusIndex,1,fig)
                    set(ud.legend.legendline,'color',...
                        ud.filt(ud.focusIndex).lineinfo.color)
                else
                    sptlegend('setvalue',ud.focusline,ud.focusIndex,1,fig)
                end
                set(ud.legend.legendline,'linestyle',...
                    ud.filt(ud.focusIndex).lineinfo.linestyle)
            end
            
        end   % newly selected filter(s) (f(ind)) doesn't equal ud.filt
    end   % filter viewer exists - fig is not empty
    
%------------------------------------------------------------------------
% enable = filtview('action',verb.action)
%  respond to button push in SPTool
% possible actions are
%    'view'
%
case 'action'
    SPTfig = gcf;
    fig = findobj('type','figure','tag','filtview');
    
    % get all filters (f) and the indexes (ind) of the selected filters
    [f,ind] = sptool('Filters',1,SPTfig);

    if isempty(fig)  % create the filter viewer
        filtview(f(ind))
    else             % set filter viewer's visibility 'ON'
        set(fig,'visible','on')
        figure(fig)
        ud = get(fig,'userdata');
        if ~isequal(f(ind),ud.filt)
            ud.filt = f(ind);
            ud.prefs.Fs = sprintf('%.9g',max([f(ind).Fs]));
            set(ud.ht.Fsedit,'string',ud.prefs.Fs)
            set(fig,'userdata',ud)
            filtview('plots',ud.prefs.plots,fig)

            ud.prefs.Fs = sprintf('%.9g',max([f(ind).Fs]));
            [FsStr filtLabelStr] = filtFsLabelStrs(ud.prefs,ud.ht,ud.filt);
            set(ud.ht.filterLabel,'string',filtLabelStr)
            set(ud.ht.Fsedit,'string',FsStr) 
            set(fig,'userdata',ud)
        end
    end

%------------------------------------------------------------------------
% filtview('SPTclose',verb.action)
%  respond to SPTool closing
% possible actions are
%    'view'
%
case 'SPTclose'
    fig = findobj('type','figure','tag','filtview');
    if ~isempty(fig)  % destroy the filtview tool
        ud = get(fig,'userdata');
        delete(fig)
    end
%------------------------------------------------------------------------
% filtview('print')
%  print contents of filtview (assumed in gcf)
%
case 'print'
    

%------------------------------------------------------------------------
% filtview('help')
% Callback of help button in toolbar
%
case 'help'
    fig = gcf;
    ud = get(fig,'userdata');
    if ud.pointer ~= 2   % if not in help mode
        % enter help mode
        saveEnableControls = [ud.legend.legendpopup
                              ud.legend.legendbutton
                              ud.ht.magpop
                              ud.ht.phasepop];
        ax = [ud.ht.a ud.toolbar.toolbar];
        titleStr = 'Filter Viewer Help';
        helpFcn = 'fvhelpstr';
        spthelp('enter',fig,saveEnableControls,ax,titleStr,helpFcn)
    else
        spthelp('exit')
    end
    
%------------------------------------------------------------------------
% errstr = filtview('setprefs',panelName,p)
% Set preferences for the panel with name panelName
%
% Inputs:
%   panelName - string; must be either 'ruler','color', 'filtview1', 
%               or 'filtview2'
%              (see sptprefreg for definitions)
%   p - preference structure for this panel
%
case 'setprefs'
    errstr = '';
    panelName = varargin{2};
    p = varargin{3};
    % first do error checking
    switch panelName        
    case 'filtview1'
        arbitrary_obj = {'arb' 'obj'};
        nfft = evalin('base',p.nfft,'arbitrary_obj');
        if isequal(nfft,arbitrary_obj)
            errstr = 'Sorry, the FFT Length you entered could not be evaluated';
        elseif isempty(nfft) | (round(nfft)~=nfft | nfft<=0 | ~isreal(nfft))
            errstr = ['The FFT Length must be a positive integer.'];
        end
        if isempty(errstr)
            nimp = evalin('base',p.nimp,'arbitrary_obj');
            if isequal(nimp,arbitrary_obj)
                errstr = 'Sorry, the Time Response Length you entered could not be evaluated';
            elseif ~isempty(nimp) & (round(nimp)~=nimp | nimp<=0 | ~isreal(nimp))
                errstr = ['The Time Response Length must be a positive integer' ...
                          ' or the empty matrix ''[]'' (to get the default value).'];
            end
        end
        if isempty(errstr) & (p.freqscale == 2 & p.freqrange == 3)
            errstr = ['You can''t have frequency log scaling with a negative ' ...
                      'frequency range.'];
        end
    case 'filtview2'  % tiling
    end
    
    varargout{1} = errstr;
    if ~isempty(errstr)
        return
    end
        
    % now set preferences
    fig = findobj('type','figure','tag','filtview');
    if ~isempty(fig)
        ud = get(fig,'userdata');
        newprefs = ud.prefs;
        switch panelName
        case 'ruler'
	    markerStr = { '+' 'o' '*' '.' 'x' ...
               'square' 'diamond' 'v' '^' '>' '<' 'pentagram' 'hexagram'}';
            newprefs.ruler.color = p.rulerColor;
            newprefs.ruler.marker = markerStr{p.rulerMarker};
            newprefs.ruler.markersize = p.markerSize;
            
            if ud.prefs.tool.ruler
                rc = evalin('base',newprefs.ruler.color);
                set(ud.ruler.lines,'color',rc);
                set(ud.ruler.markers,'color',rc,'marker',newprefs.ruler.marker,...
                   'markersize',evalin('base',newprefs.ruler.markersize))
            end
        case 'color'
            newprefs.colororder = p.colorOrder;
            newprefs.linestyleorder = p.linestyleOrder;
            ud.colororder = num2cell(evalin('base',newprefs.colororder),2);
            ud.linestyleorder = num2cell(evalin('base',newprefs.linestyleorder),2);            
        case 'filtview1'
            newprefs.tool.zoompersist = p.zoomFlag;
            newprefs.tool.ruler = p.rulerEnable;
            newprefs.nfft = evalin('base',p.nfft);
            newprefs.nimp = evalin('base',p.nimp);
            
            set(ud.ht.magpop,'value',p.magscale)
            set(ud.ht.phasepop,'value',p.phaseunits)
            set(ud.ht.fscalepop,'value',p.freqscale)
            set(ud.ht.frangepop,'value',p.freqrange)
                        
            newprefs.magmode = {'linear' 'log' 'decibels'};
            newprefs.magmode = newprefs.magmode{p.magscale};
            newprefs.phasemode = {'degrees' 'radians'};
            newprefs.phasemode = newprefs.phasemode{p.phaseunits};
            newprefs.freqscale = {'linear' 'log'};
            newprefs.freqscale = newprefs.freqscale{p.freqscale};
            newprefs.freqrange = p.freqrange;

            % enable / disable ruler
            if ud.prefs.tool.ruler ~= newprefs.tool.ruler
                if newprefs.tool.ruler
                    % Enable ruler and ruler popupmenu 
                    rulerPrefs = sptool('getprefs','ruler');
                    typeStr = {'vertical','horizontal','track','slope'};
                    ud.prefs.ruler.type = typeStr{rulerPrefs.initialType};
                    set(fig,'userdata',ud)

                    % Account for the case where the filter was cleared
                    % while viewing it in the filter viewer
                    if isfield(ud,'filt.tf.den')
                        realFilterFlag = (isreal(ud.filt(ud.focusIndex).tf.num)...
                            & isreal(ud.filt(ud.focusIndex).tf.den));
                    else
                        realFilterFlag = 1;
                    end

                    % Find mainaxes to focus rulers                    
                    [ud.mainaxes,ud.focusline,plotIndex,visPlots] = ...
                        setMainaxes(ud.mainaxes,ud.ht.a,ud.lines,realFilterFlag);
                    set(fig,'userdata',ud)

                    % Update rulerpopup; display (initialize) ruler panel
                    % and focus ruler on appropriate subplot
                    rulerPopStr = filtview('plotTitles',realFilterFlag);
                    rulerPopVal = min(plotIndex,length(rulerPopStr));
                    popupCallback = 'filtview(''rulerpopup'')';	
                    ruler('init',fig,rulerPopStr,rulerPopVal,...
                        popupCallback,ud.ht.a)
                    ud = get(fig,'userdata');
                    new_ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
                    set(fig,'userdata',new_ud)
                    ruler('newlimits',fig,plotIndex)
                    ruler('newsig',fig,plotIndex)
                    noTrackZeroPole(fig,new_ud)
                else
                    ruler('close',fig)
                end
                ud = get(fig,'userdata');
            end

        case 'filtview2'
            if p.mode1
                newprefs.tilemode = [2 3];
            elseif p.mode2
                newprefs.tilemode = [3 2];
            elseif p.mode3
                newprefs.tilemode = [6 1];
            elseif p.mode4
                newprefs.tilemode = [1 6];
            end
        end
        ud.prefs = newprefs;
        set(fig,'userdata',ud)

        fvresize(1,fig)
        if newprefs.tool.ruler
            ruler('resizebtns',fig)
        end
        fvzoom('zoomout',ud.prefs.plots,fig)
        filtview('plots',ud.prefs.plots,fig)

        % Update ruler's XY limits; limits might have changed due to
        % preferences changes
        if ud.prefs.tool.ruler & newprefs.tool.ruler
            ud = get(fig,'userdata');
            plotIndex = find(ud.mainaxes==ud.ht.a);
            new_ud = filtview('setudlimits',ud,ud.ht.a,plotIndex);
            set(fig,'userdata',new_ud)
            ruler('newlimits',fig,plotIndex)
            ruler('newsig',fig,plotIndex)
        end
    end
    
end  % of switch statement

function setstem(h,x,y)
%SETSTEM Set xdata and ydata of two handles for stem plots

    set(h(1),'xdata',x,'ydata',y)
    x = x(:);  % make it a column
    xx = x(:,[1 1 1])';
    xx = xx(:);
    n = nan;
    y = [zeros(size(x)) y(:) n(ones(length(x),1),:)]';
    set(h(2),'xdata',xx,'ydata',y(:));

function [mainaxes,focusline,plotIndex,visPlots] = ...
        setMainaxes(oldMainaxes,axesList,lineList,realDataFlag)
%SETMAINAXES Set a new axes (if mainaxes was set invisible), from 
%       the list of visible axes, to be the new mainaxes (where rulers
%       will be focused).  Otherwise, use the input OldMainaxes as the
%       new mainaxes.
% Inputs:
%   oldMainaxes - handle to previous mainaxes
%   axesList - list of axes handles of all possible subplots
%   lineList - structure containing the handles to each line
%              of all subplots
%   realDataFlag - flag indicating that line which rulers are focused on is
%                  real
% Outputs:
%   mainaxes - handle to the newly selected subplot axes
%   focusline - handle to the newly selected line
%   plotIndex - index into the list of the handles of all subplots
%   visPlots - indices of visible plots of vector containing
%              all subplots
%
    visPlots = find(strcmp(get(axesList,'visible'),'on'));
       
    if strcmp(get(oldMainaxes,'visible'),'off')
        oldMainaxes_indx = find(oldMainaxes == axesList);
        
        if ~isempty(visPlots)
            [dum,visPlotIndx] = min(mod(visPlots-oldMainaxes_indx,6));
            plotIndex  = visPlots(visPlotIndx);
            mainaxes = axesList(plotIndex);
            fig = get(mainaxes,'parent');
            focusIndex = sptlegend('value',fig);
            focusline = setFocusLine(mainaxes,lineList,plotIndex,...
                focusIndex,realDataFlag);
        else
            plotIndex  = 1;
            mainaxes = oldMainaxes;
            focusline = [];
        end
    else
        mainaxes = oldMainaxes;
        plotIndex = find(mainaxes == axesList);
        focusIndex = 1;
        focusline = setFocusLine(mainaxes,lineList,plotIndex,...
            focusIndex,realDataFlag);
    end					   

function updateRulrPopupList(fig,rulerPopStr,axesList,mainaxes,realFilterFlag)
% UPDATERULRPOPUPLIST Update the list of the ruler popupmenu and when
%	appropriate add '<none>' to the first element of the popup
%       string.
% Inputs:
%   fig - handle to the filtviewer
%   rulerPopStr - the string value of the ruler popupmenu
%   axesList - list of axes handles of all possible subplots
%   mainaxes - axes where rulers are currently focused
%   realFilterFlag - flag indicating if filter being viewed is real
%
    visPlots = find(strcmp(get(axesList,'visible'),'on'));
    if ~isempty(visPlots)
        plotIndex = find(mainaxes == axesList);
        rulerPopVal = plotIndex + (~realFilterFlag & plotIndex == 6);
    else    
        rulerPopStr = {'<none>',rulerPopStr{:}};
        rulerPopVal = 1;    
    end
    ruler('setpopup',fig,rulerPopStr,rulerPopVal)
           
function focusLine = setFocusLine(mainaxes,lineList,plotIndex,...
                                                 focusIndex,realDataFlag)
% SETFOCUSLINE Sets the focus line
% Inputs:
%   mainaxes - axes where rulers are currently focused
%   lineList - structure containing the handles to each line
%              of all subplots
%   plotInde - index indicating which subplot is selected
%   focusIndex - index indicating which filter is being viewed
%   realDataFlag - flag indicating that line where rulers are focused is
%                  real
% Outputs:
%   focusLine - the new line which the rulers are focused on
%

    % The following is necessary in case where there are 2 plots
    % being viewed; all filters are cleared (in SPTool) and then the
    % mainaxes plot (where the rulers were focused) is deselected .  This
    % means that mainaxes was 'on' but all the lines were empty, hence,
    % focusline should be set to [].
    allLinesEmpty = 1;
    if ~isempty(lineList)
        h = struct2cell(lineList(focusIndex));
        h = [h{:}];
        if ~isempty(h), allLinesEmpty = 0; end
    end

    if strcmp(get(mainaxes,'visible'),'off') | allLinesEmpty
        focusLine = [];
    else 
        switch plotIndex
        case 1
            focusLine = lineList(focusIndex).mag;
        case 2
            focusLine = lineList(focusIndex).phase;
        case 3
            focusLine = lineList(focusIndex).grpdelay;
        case 4           
            if ~isempty(get(lineList(focusIndex).z,'xdata'))
                focusLine = lineList(focusIndex).z;
            else
                focusLine = lineList(focusIndex).p;
            end
        case 5
            if realDataFlag
                focusLine = lineList(focusIndex).imp;
            else
                focusLine = lineList(focusIndex).impc;
            end
        case 6
            if realDataFlag
                focusLine = lineList(focusIndex).step;    
            else
                focusLine = lineList(focusIndex).stepc;
            end
        end
    end
    
function realdataFlag = realdataFlag(selectedLine,allLines,focusIndex)
% REALDATAFLAG Determines if the line chosen for the rulers to focus on is
% the real or imaginary part of the impulse or step response.
% Inputs:
%   allLines - list of all possible line objects in all subplots
%   focusIndex - index into list of filters
% Ouputs:
%   realdataFlag - flag indicating if the data is real (1 = real)
%
    l = selectedLine;
    imagLines = {'impc' 'impstemc' 'stepc' 'stepstemc'};
    realdataFlag = 1;
    for i = 1:length(imagLines)
        if ~isempty(getfield(allLines(focusIndex),imagLines{i}))...
                & (l == getfield(allLines(focusIndex),imagLines{i}))
            realdataFlag = 0;
            break
        end
    end
    
function noTrackZeroPole(fig,ud)
% NOTRACKZEROPOLE If in zero-pole plot don't allow slope and track rulers.
% Inputs:
%   fig - figure handle of client, filter viewer
%   ud - userdata of the client, filter viewer
%
    if (ud.mainaxes == ud.ht.a(4))
        ruler('allowTrack','off',fig)
    else
        ruler('allowTrack','on',fig)
    end

function bool = flisequal(fig,focusline,l)
% FLISEQUAL - FOCUS LINE IS EQUAL
%  True if focusline and l are "virtually" equivalent
%  Usually this is only true if l is actually equal to focusline
%  but when focusline is any of lines.imp, impc, stem, stemc, or z (for
%  zero-pole plot) l is considered "equal" if it is impstem, impstemc,
%  stepstem, stepstemc or p respectively.
% Inputs:
%   fig - figure handle of client (filter viewer)
%   focusline - handle of line focused on by rulers
%   l - handle of line clicked on by the mouse pointer
%   selected filters
%
     if isequal(focusline,l)
         bool = 1;
     else
         ud = get(fig,'userdata');
         tagSets = {
                    {'impline' 'implinestem'} 
                    {'implinec' 'implinestemc' 'implinedotsc'}
                    {'stepline' 'steplinestem'}
                    {'steplinec' 'steplinestemc' 'steplinedotsc'}
                    {'zerosline' 'polesline' 'unitcircle'}
                   };
         lineTag = get(l,'tag');
         flineTag = get(focusline,'tag');
         bool = 0;
         for i = 1:length(tagSets)
             if ~isempty(find(strcmp(lineTag, tagSets{i})))
                 bool = 1;
                 break
             end
         end
     end

function [lines] = emptyLinesStruct
% EMPTYLINESSTRUCT Create scalar lines structure and initialize to []
    
    lines.mag = [];   
    lines.phase = [];   
    lines.grpdelay = [];   
    lines.z = [];   
    lines.p = [];   
    lines.imp = [];   
    lines.impstem = [];   
    lines.impc = [];   
    lines.impstemc = [];   
    lines.step = [];   
    lines.stepstem = [];   
    lines.stepc = [];   
    lines.stepstemc = [];   

function [need_update,lines,focusIndex] = ...
          redundantFilters(newFilts,oldFiltSelection,oldLines,oldFocusIndex)
% REDUNDANTFILTERS - Determines if the new selection of filters contains
%        filters that were previously selected.  If so, and the filter
%        response has not changed, then it does not calculate the filter
%        response of that filter again.  Also, this functions uses lines of
%        old filters for the newly selected filters - this avoids deleting
%        and then re-creating lines.
% Inputs:
%   newFilts - new selection of filters
%   oldFiltSelection - old selection of filters (ud.filt)
%   oldLines - old lines (ud.lines)
%   oldFocusIndex - old focus index (ud.focusIndex)
% Ouputs:
%   lines - new ud.lines with possibly some recycled lines
%   focusIndex - new focus index
%
    % Find overlapping filters between new selection and old selection
    [c,ia,ib] = intersect(char({oldFiltSelection.label}),...
                          char({newFilts.label}),'rows');

    if isempty(oldFocusIndex) | isempty(ia)
        focusIndex = 1;     % arbitrarily select 1st item
    else
        if any(oldFocusIndex==ia)
            focusIndex = ib(find(oldFocusIndex == ia));
        else
            if oldFocusIndex > length(newFilts) 
                % Last filter in SPTool list was unselected; select the first
                focusIndex = 1;
            else
                focusIndex = min(find(ia > oldFocusIndex));
            end
        end
    end
    
    for i=length(ia):-1:1
        if ~isequal(oldFiltSelection(ia(i)),newFilts(ib(i)))
            ia(i) = [];
            ib(i) = [];
        end
    end
    
    % at this point, don't need to update ud.filt(ib)
    [ib,ib_sort_ind] = sort(ib);
    ia = ia(ib_sort_ind);
    need_update = 1:length(newFilts);
    need_update(ib) = [];

    % initialize empty line struct array
    lines = [];
    lines = emptyLinesStruct; % re-create lines
    lines(length(newFilts)) = lines(1);
    
    if ~isempty(ia)
        lines(ib) = oldLines(ia);
    end
    oldLines(ia) = [];
    
    % Delete any oldLines that we can't use. Won't enter loop unless we
    % have a surplus of oldLines to delete
    for j = (length(need_update)+1):length(oldLines)         
        h = struct2cell(oldLines(j));
        h = [h{:}];
        delete(h)
    end        
    
    % Use any oldLines that we can by copying them to ud.lines:
    for i = 1:min(length(oldLines),length(need_update))
        lines(need_update(i)) = oldLines(i);
    end

function [xlim1,xlim2,ylim1,ylim2] = zeropolePlotLims(filtStruct)
% ZEROPOLEPLOTLIMS Set the XY limits to the largest values of the plots
%        currently being viewed

    xlim1 = inf; xlim2 = -inf;
    ylim1 = inf; ylim2 = -inf;

    for i = 1:length(filtStruct)
        if ~isempty(filtStruct(i).zpk)
            xlim1 = min(real([xlim1; filtStruct(i).zpk.z(:); filtStruct(i).zpk.p(:)]));
            xlim2 = max(real([xlim2; filtStruct(i).zpk.z(:); filtStruct(i).zpk.p(:)]));
            ylim1 = min(imag([ylim1; filtStruct(i).zpk.z(:); filtStruct(i).zpk.p(:)]));
            ylim2 = max(imag([ylim2; filtStruct(i).zpk.z(:); filtStruct(i).zpk.p(:)]));
        end 
    end

    if isempty(xlim1)
        xlim1 = -1.5;
    end
    if isempty(xlim2)
        xlim2 = 1.5;
    end
    if isempty(ylim1)
        ylim1 = -1.5;
    end
    if isempty(ylim2)
        ylim2 = 1.5;
    end
    if xlim1 == xlim2
        xlim1 = xlim1-1;
        xlim2 = xlim2+1;
    end
    if ylim1 == ylim2
        ylim1 = ylim1-1;
        ylim2 = ylim2+1;
    end
    
function [FsStr,filtLabelStr] = filtFsLabelStrs(prefsStruct,uiHandles,...
                                                                filtsStruct)
% FILTFSLABELSTRS - Determine the string to be used for the sampling
%       frequency and the currently selected filter names.
% Inputs:
%   prefsStruct - userdata structure containing filter viewer preferences
%                (ud.prefs)
%   uiHandles - filter viewers uicontrol handles (ud.ht)
%   filtsStruct - the array of selected filter structures (ud.filt)
% Outputs:
%   FsStr - the string "Fs=" (for single filter) or "Maximum Fs =" (for
%           multiple filters)
%   filtLabelStr - the names of the filters currently selected, if they fit
%                  in the allowed space, or the string "n filters
%                  selected", where n is the number of filters selected.
%
    labelpos = get(uiHandles.filterLabel,'position');
    numFilts = length(filtsStruct);
    
    if (numFilts == 1) 
        FsStr = ['Fs = ' prefsStruct.Fs];
        filtLabelStr = ['Filter: ' filtsStruct(1).label];
    else
        if isequal([filtsStruct.Fs], ...  % All Fs is equal
                filtsStruct(1).Fs*ones(1,length(filtsStruct)))
            FsStr = ['Fs = ' prefsStruct.Fs];
        else
            FsStr = ['Maximum Fs = ' prefsStruct.Fs];
        end

        filtsStr = '';
        for i = 1:numFilts  % Loop through the selected filters
            if numFilts > 1
                if (i ~= 1), filtsStr = [filtsStr ', ']; end
                filtsStr = [filtsStr filtsStruct(i).label];
                filtLabelStr = ['Filters: ' filtsStr];           
            end
        end     % Looping through the selected filters
        
        % Determine if all the filter names will fit in space allowed
        tempstr = get(uiHandles.filterLabel,'string');
        set(uiHandles.filterLabel,'string',filtLabelStr)
        labelext = get(uiHandles.filterLabel,'extent');
        set(uiHandles.filterLabel,'string',tempstr)
        if labelext(3) > labelpos(3)+5
            filtLabelStr = [sprintf('%d', numFilts),' filters selected'];
        end
    end

function newPopupVal = cmplxFiltPopupVal(currentPopupVal, newPlottitles, ...
                                                          currentPlotTitles)
% CMPLXFILTPOPUPVAL - determine what the ruler popup value should be in the
%        cases were user switches from a complex to a real filter or vice
%        versa.
%

    newPopupVal = currentPopupVal;
    if length(newPlottitles) == length(currentPlotTitles)
        % going from complex-filter --> complex-filter   OR
        % going from real-filter    --> real-filter
        % newPopupVal does not change...
    elseif length(newPlottitles) > length(currentPlotTitles)
        % going from real-filter    --> complex-filter
        if currentPopupVal == 6
            newPopupVal = currentPopupVal + 1;
        end
    else % going from complex-filter --> real-filter
        switch currentPopupVal
        case 6,     newPopupVal = 5;
        case {7,8}, newPopupVal = 6;
        end
    end

function bringToFront(fig,focusIndx)
%bringToFront
%  reorders children of parent axis of h so that 
%   the objects with handles in h are just above all the objects
%   except for the ruler lines

   ud = get(fig,'userdata');

   for nAxis = 1:length(ud.ht.a)
       ax = ud.ht.a(nAxis);
       ch = get(ax,'children');
   
       rulerHndls = [];
       if ud.prefs.tool.ruler & (ud.mainaxes == ax)
           % make sure ruler lines are on top of stacking order
           rulerHndls = [ud.ruler.lines(:); ud.ruler.markers(:)];
       end
   
       h = [];
       for i = 1:length(ud.lines)
           if  (i==focusIndx)        % Create a vector of handles which will
               switch(nAxis)         % follow the rulers' handles in the 
               case 1                % stacking order of the children
                   h = [h;ud.lines(i).mag];
               case 2
                   h = [h;ud.lines(i).phase];
               case 3 
                   h = [h;ud.lines(i).grpdelay];
               case 4
                   h = [h;ud.lines(i).z; ud.lines(i).p];
               case 5
                   h = [h;ud.lines(i).imp; ud.lines(i).impc; ...
                   ud.lines(i).impstem; ud.lines(i).impstemc;h];
               case 6 
                   h = [h;ud.lines(i).step; ud.lines(i).stepc; ...
                       ud.lines(i).stepstem; ud.lines(i).stepstemc];
               end
           end 
       end

       orig_ch = ch;       
       for i=1:length(h)
           ch(find(ch==h(i))) = []; % Remove handles to lines of focused filter
       end
       ch = [h;ch];                % Prepend handles to lines of focused filter
       ch1 = ch;
       
       for i=1:length(rulerHndls)
           ch1(find(ch1==rulerHndls(i))) = []; % Remove handles of rulers
       end
       ch1 = [rulerHndls; ch1(:)]; % Prepend handles of ruler lines/markers*
       if ~isequal(ch1,orig_ch)  
           % avoid redraw if child order hasn't changed
           set(ax,'children',ch1)
       end
   end

