function Status = trackpz(Editor,event)
%TRACKPZ  Tracks compensator pole or zero during mouse drag.
%
%   See also SISOTOOL.

%   Author(s): P. Gahinet
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.12 $  $Date: 2000/08/16 18:15:34 $

persistent MovedGroup PZID Ts TransAction
persistent AutoScaleOn LocusLims 

HG = Editor.HG;

% Process event
switch event 
    
case 'init'
    % Initialization for compensator pole/zero drag
    % Identify selected root 
    [MovedGroup,PZID,Y] = LocalGetSelection(gcbo);
    Ts = getTs(Editor.LoopData);
    
    % Initialize parameters used to adjust limits/pointer position
    AutoScaleOn = all(strcmp([Editor.XlimMode;Editor.YlimMode],'auto'));
    if AutoScaleOn,
        relocptr('init',HG.PlotAxes)
        LocusLims = get(HG.PlotAxes,{'Xlim','Ylim'});
        LocusLims = [LocusLims{:}];
    end
    
    % Track root location in status bar 
    Status = LocalTrackStatus(MovedGroup,PZID,Ts,Y,Editor.FrequencyUnits);
    
    % Broadcast MOVEPZ:init event
    % RE: Sets RefreshMode='quick' and installs listeners on Pole/Zero property of selected group
    Editor.up.send('MovePZ',sisodata.dataevent(Editor.up,'MovePZ',{'init',MovedGroup}));
    
    % Start transaction
    TransAction = handle.transaction(get(findpackage('sisodata'),'DefaultDatabase'));
    set(TransAction,'Name',sprintf('Move %s',PZID),'OperationStore','on',...
        'InverseOperationStore','on','Compression','on');
    
case 'acquire'
    % Acquire new pole/zero position 
    CP = get(HG.PlotAxes,'CurrentPoint');
    
    % Clear open loop model (stale)
    Editor.LoopData.OpenLoop = [];
    
    % Update data of moved PZGROUP 
    NewLoc = movepz(Editor,MovedGroup,PZID,CP(1,1),CP(1,2),Ts);
    
    % BroadcastPZDataChanged event (triggers plot updates)
    MovedGroup.send('PZDataChanged',...
        handle.EventData(MovedGroup,'PZDataChanged'));
    
    % Track root location in status bar 
    Status = LocalTrackStatus(MovedGroup,PZID,Ts,CP(1,2),Editor.FrequencyUnits);
    
    % Adjust axis limits if dragged pole/zero gets out of focus
    if AutoScaleOn,
        out = checklims(Editor,LocusLims,NewLoc);  [LocusLims,MovePtr] = deal(out{:});
        if MovePtr
            relocptr('move',CP(1,1),CP(1,2),LocusLims)
        end
    end
    
case 'finish'
    % Button up event.   
    Status = '';  % ignored
    
    % Commit and stack transaction
    register(Editor.LoopData,TransAction);
    TransAction = [];   % release persistent objects
    
    % Broadcast MOVEPZ:finish event (exit RefreshMode=quick,...)  
    Editor.up.send('MovePZ',...
        sisodata.dataevent(Editor.up,'MovePZ',{'finish'}));
    
    % Update status and command history
    Str = movelog(MovedGroup,PZID,Ts);
    Editor.up.send('StatusChanged',...
        sisodata.dataevent(Editor.up,'StatusChanged',...
        {sprintf('%s\nRight-click on plots for more design options.',Str),Str}));
    MovedGroup = [];
    
    % Trigger global update
    dataevent(Editor.LoopData,'all');
    
end


%----------------- Local functions -----------------

%%%%%%%%%%%%%%%%%%%%%
% LocalGetSelection %
%%%%%%%%%%%%%%%%%%%%%
function [MovedGroup,PZID,Y] = LocalGetSelection(CurrentObj)
% Identifies selected PZGROUP object (pole/zero group)

% Moved PZVIEW object
MovedPZVIEW = get(CurrentObj,'UserData');
if any(MovedPZVIEW.Zero==CurrentObj)
    PZID = 'Zero';
else
    PZID = 'Pole';
end

% Moved PZGROUP
MovedGroup = MovedPZVIEW.GroupData;
Y = get(CurrentObj,'Ydata');


%%%%%%%%%%%%%%%%%%%%
% LocalTrackStatus %
%%%%%%%%%%%%%%%%%%%%
function Status = LocalTrackStatus(Group,PZID,Ts,Y,FreqUnits)
% Display info about moved pole/zero

% Defs
Spacing = blanks(5);

switch Group.Type
case 'Notch'
    % Custom display for notch filters
    Text = sprintf('Drag this compensator %s to alter the notch location/shape.',...
        lower(PZID));
    [Wn,Zeta] = damp([Group.Zero(1);Group.Pole(1)],Ts);
    Wn = unitconv(Wn,'rad/sec',FreqUnits);
    Status = ...
        sprintf('%s\nNatural Frequency: %0.3g %s%sZero Damping: %0.3g%sPole Damping: %0.3g',...
        Text,Wn(1),FreqUnits,Spacing,Zeta(1),Spacing,Zeta(2));
    
case 'Complex'
    % Complex pair
    Text = sprintf('Drag this compensator %s to the desired location.',lower(PZID));
    R = get(Group,PZID);
    if Y>=0,
        R = R(1); Sign = '+';
    else
        R = R(2); Sign = '-';
    end
    [Wn,Zeta] = damp(R,Ts);
    Wn = unitconv(Wn,'rad/sec',FreqUnits);
    Status = ...
        sprintf('%s\nCurrent location: %0.3g %s %0.3gi%sDamping: %0.3g%sNatural Frequency: %0.3g %s',...
        Text,real(R),Sign,abs(imag(R)),Spacing,Zeta,Spacing,Wn,FreqUnits);
    
otherwise
    % Real pole/zero
    Text = sprintf('Drag this compensator %s to the desired location.',lower(PZID));
    R = get(Group,PZID);
    if Ts
        Wn = unitconv(damp(R,Ts),'rad/sec',FreqUnits);
        Status = sprintf('%s\nCurrent location: %0.3g%sNatural Frequency: %0.3g %s',...
            Text,R,Spacing,Wn,FreqUnits);
    else
        Status = sprintf('%s\nCurrent location: %0.3g',Text,R);
    end
end



