function h = addmenu(Editor,Anchor,MenuType)
%ADDMENU  Creates generic editor context menus.
% 
%   H = ADDMENU(EDITOR,ANCHOR,MENUTYPE) creates a menu item, related
%   submenus, and associated listeners.  The menu is attached to the 
%   parent object with handle ANCHOR.

%   Author(s): P. Gahinet
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.11 $ $Date: 2000/08/02 16:06:29 $

switch MenuType
    
case 'add'
    % Add Pole/Zero menu
    LoopData = Editor.LoopData;
    h = uimenu(Anchor,'Label',sprintf('Add'));
    uimenu(h,'Label',sprintf('Real Pole'),...
        'Callback',{@LocalAddPZ Editor 'Real' 'Pole'});
    uimenu(h,'Label',sprintf('Complex Pole'),...
        'Callback',{@LocalAddPZ Editor 'Complex' 'Pole'});
    uimenu(h,'Label',sprintf('Integrator'),...
        'Callback',{@LocalAddInt Editor});
    uimenu(h,'Label',sprintf('Real Zero'),...
        'Callback',{@LocalAddPZ Editor 'Real' 'Zero'}, ...
        'Separator','on');
    uimenu(h,'Label',sprintf('Complex Zero'),...
        'Callback',{@LocalAddPZ Editor 'Complex' 'Zero'});
    uimenu(h,'Label',sprintf('Differentiator'),...
        'Callback',{@LocalAddDiff Editor});
    uimenu(h,'Label',sprintf('Lead'),...
        'Callback',{@LocalAddPZ Editor 'Lead' ''}, ...
        'Separator','on');
    uimenu(h,'Label',sprintf('Lag'),...
        'Callback',{@LocalAddPZ Editor 'Lag' ''});
    uimenu(h,'Label',sprintf('Notch'),...
        'Callback',{@LocalAddPZ Editor 'Notch' ''});
        
    % Add listeners to edit mode changes
    lsnr = handle.listener(Editor,findprop(Editor,'EditMode'),...
        'PropertyPostSet',{@LocalModeChanged 'add' h});
    set(h,'UserData',lsnr)  % Anchor listeners for persistency
   
case 'constraint'
    % Design constraints
    h = uimenu(Anchor,'Label',sprintf('Design Constraints...'), ...
        'Callback',{@LocalSetConstr Editor});
    
case 'delete'
    % Delete Pole/Zero menu
    h = uimenu(Anchor,'Label',sprintf('Delete Pole/Zero'), ...
        'Callback',{@LocalDeletePZ Editor});
    
    % Add listeners to edit mode changes
    lsnr = handle.listener(Editor,findprop(Editor,'EditMode'),...
        'PropertyPostSet',{@LocalModeChanged 'delete' h});
    set(h,'UserData',lsnr)  % Anchor listeners for persistency
    
case 'edit'
    % Edit Compensator
    h = uimenu(Anchor,'Label',...
        sprintf('Edit Compensator...'),'Callback',{@LocalShowEditor Editor});
    
case 'grid'
    % Grid
    h = uimenu(Anchor,'Label',sprintf('Grid'),'Callback',{@LocalSetGrid Editor});
    lsnr = handle.listener(Editor,findprop(Editor,'Grid'),...
        'PropertyPostSet',{@GridMenuState h});
    % Anchor listeners for persistency
    set(h,'UserData',lsnr)
    
case 'property'
    % Properties
    h = uimenu(Anchor,'Label',sprintf('Properties...'),...
        'Callback',{@LocalOpenEditor Editor});
    
case 'zoom'
    % Zoom
    h = uimenu(Anchor,'Label',sprintf('Zoom'));
    uimenu(h,'label',sprintf('X-Y'),'Callback',{@LocalZoomIn Editor});
    uimenu(h,'Label',sprintf('In-X'),'Callback',{@LocalZoomIn Editor});
    uimenu(h,'label',sprintf('In-Y'),'Callback',{@LocalZoomIn Editor});
    hout = uimenu(h,'label',sprintf('Out'),'Enable','off',...
        'Callback',{@LocalZoomOut Editor});
    
    % Add listeners to edit mode changes
    lsnr(1) = handle.listener(Editor,findprop(Editor,'EditMode'),...
        'PropertyPostSet',{@LocalModeChanged 'zoom' h});
    lsnr(2) = handle.listener(Editor,findprop(Editor,'XlimMode'),...
        'PropertyPostSet',{@LocalZoomOutEnable hout});
    lsnr(3) = handle.listener(Editor,findprop(Editor,'YlimMode'),...
        'PropertyPostSet',{@LocalZoomOutEnable hout});
    set(h,'UserData',lsnr)  % Anchor listeners for persistency
   
end


%----------------------------- Listener callbacks ----------------------------

%%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalModeChanged %%%
%%%%%%%%%%%%%%%%%%%%%%%%
function LocalModeChanged(hProp,event,MenuMode,hMenu)
% Update state of right-click menu (check mark)
checkmenu(event.AffectedObject,MenuMode,hMenu);


%%%%%%%%%%%%%%%%%%%%%
%%% GridMenuState %%%
%%%%%%%%%%%%%%%%%%%%%
function GridMenuState(hProp,event,hMenu)
% Updates grid menu state
set(hMenu,'Checked',event.NewValue)


%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalZoomOutEnable %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%
function LocalZoomOutEnable(hProp,event,hZoomOut)
% Disable Zoom:Out menu when XlimMode=YlimMode=auto
Editor = event.AffectedObject;
if all(strcmp(Editor.XlimMode,'auto')) & ...
        all(strcmp(Editor.YlimMode,'auto'))
    set(hZoomOut,'Enable','off')
else
    set(hZoomOut,'Enable','on')
end


%----------------------------- Callback actions ----------------------------

%%%%%%%%%%%%%%%%%%%
%%% LocalAddInt %%%
%%%%%%%%%%%%%%%%%%%
function LocalAddInt(hSrc,event,Editor)
% Add integrator
LoopData = Editor.LoopData;

% Abort global modes and return to idle mode
send(Editor.up,'LocalModeChange',...
    handle.EventData(Editor.up,'LocalModeChange'));
Editor.EditMode = 'idle';

% Start transaction
T = handle.transaction(get(findpackage('sisodata'),'DefaultDatabase'));
set(T,'Name','Add Integrator','OperationStore','on','InverseOperationStore','on');

% Add integrator
addpz(LoopData.Compensator,'Real',zeros(0,1),(LoopData.Compensator.Ts~=0));

% Register transaction 
register(Editor.LoopData,T);

% Notify of loop data change
dataevent(LoopData,'all');

% Update status and history
Status = sprintf('Added an integrator to the compensator.');
Editor.up.send('StatusChanged',...
    sisodata.dataevent(Editor.up,'StatusChanged',{Status,Status}));


%%%%%%%%%%%%%%%%%%%%
%%% LocalAddDiff %%%
%%%%%%%%%%%%%%%%%%%%
function LocalAddDiff(hSrc,event,Editor)
% Add differentiator
LoopData = Editor.LoopData;

% Abort global modes and return to idle mode
send(Editor.up,'LocalModeChange',...
    handle.EventData(Editor.up,'LocalModeChange'));
Editor.EditMode = 'idle';

% Start transaction
T = handle.transaction(get(findpackage('sisodata'),'DefaultDatabase'));
set(T,'Name','Add Differentiator','OperationStore','on','InverseOperationStore','on');

% Add integrator
addpz(LoopData.Compensator,'Real',(LoopData.Compensator.Ts~=0),zeros(0,1));

% Register transaction 
register(Editor.LoopData,T);

% Notify of loop data change
dataevent(LoopData,'all');

% Update status and history
Status = sprintf('Added a differentiator to the compensator.');
Editor.up.send('StatusChanged',...
    sisodata.dataevent(Editor.up,'StatusChanged',{Status,Status}));


%%%%%%%%%%%%%%%%%%
%%% LocalAddPZ %%%
%%%%%%%%%%%%%%%%%%
function LocalAddPZ(hSrc,event,Editor,Type,ID)
% Starts Add Pole/Zero operation (hSrc = submenu handle)

AddType = {Type,ID};

% Exiting Add mode? (unchecking menu)
ExitingMode = strcmp(Editor.EditMode,'add') & isequal(Editor.ModeData,AddType);

% Abort global modes (may reset EditMode to idle)
send(Editor.up,'LocalModeChange',...
    handle.EventData(Editor.up,'LocalModeChange'));

% Return to idle if already in Add mode (resets menu and pointer)
if strcmp(Editor.EditMode,'add')
    Editor.EditMode = 'idle';  
end

% Enter 'add' mode
if ~ExitingMode
    % RE: Updating EditMode triggers menu update and resets pointer
    Editor.ModeData = AddType;
    Editor.EditMode = 'add';    
    % Evaluate WBM function once to set correctly pointer
    mouseevent(Editor,'wbm','',0,0);
end


%%%%%%%%%%%%%%%%%%%%%
%%% LocalDeletePZ %%%
%%%%%%%%%%%%%%%%%%%%%
function LocalDeletePZ(hSrc,event,Editor)
% Starts Delete Pole/Zero operation

% Exiting Delete mode? (unchecking menu)
ExitingMode = strcmp(Editor.EditMode,'delete');

% Abort global modes (may reset EditMode to idle)
send(Editor.up,'LocalModeChange',...
    handle.EventData(Editor.up,'LocalModeChange'));

% Update edit mode
if ExitingMode
    % Unchecking menu: revert to idle
    Editor.EditMode = 'idle';  
else
    % Enter 'delete' mode (triggers menu update and resets pointer)
    Editor.EditMode = 'delete';  
    % Evaluate WBM function once to set correctly pointer
    mouseevent(Editor,'wbm','',0,0);
end    


%%%%%%%%%%%%%%%%%%%
%%% LocalZoomIn %%%
%%%%%%%%%%%%%%%%%%%
function LocalZoomIn(hSrc,event,Editor)
% Zoom menu callback (hSrc = submenu handle)

ZoomType = lower(get(hSrc,'Label'));

% Exiting Zoom mode? (unchecking menu)
ExitingMode = strcmp(Editor.EditMode,'zoom') & isequal(Editor.ModeData,ZoomType);

% Abort global modes (may reset EditMode to idle)
send(Editor.up,'LocalModeChange',...
    handle.EventData(Editor.up,'LocalModeChange'));

% Return to idle if already in Zoom mode (resets menu and pointer)
if strcmp(Editor.EditMode,'zoom')
    Editor.EditMode = 'idle';  
end

% Enter zoom mode
if ~ExitingMode
    % RE: Updating EditMode triggers menu update and resets pointer
    Editor.ModeData = ZoomType;  
    Editor.EditMode = 'zoom';  
    % Evaluate WBM function once to set correctly pointer
    mouseevent(Editor,'wbm','',0,0);
end


%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalShowEditor %%%
%%%%%%%%%%%%%%%%%%%%%%%
function LocalShowEditor(hSrc,event,Editor)
% Bring up PZ editor
send(Editor.up,'ShowPZEditor');  % notify editor's parent


%%%%%%%%%%%%%%%%%%%%%%
%%% LocalSetConstr %%%
%%%%%%%%%%%%%%%%%%%%%%
function LocalSetConstr(hSrc,event,Editor)
% Bring up Design Constraint editor
% REVISIT: merge
HG = Editor.HG;
ConstrEditor = HG.ConstraintDialog;
if isempty(ConstrEditor) | ~ishandle(ConstrEditor)
    editconstr(Editor);
else
    figure(ConstrEditor);
end


%%%%%%%%%%%%%%%%%%%%
%%% LocalZoomOut %%%
%%%%%%%%%%%%%%%%%%%%
function LocalZoomOut(hSrc,event,Editor)
% Zoom out callback (hSrc = submenu handle)
zoomout(Editor);


%%%%%%%%%%%%%%%%%%%%
%%% LocalSetGrid %%%
%%%%%%%%%%%%%%%%%%%%
function LocalSetGrid(hSrc,event,Editor)
% Grid menu callback (hSrc = menu handle)
if strcmp(get(hSrc,'Checked'),'on')
    Editor.Grid = 'off';
else
    Editor.Grid = 'on';
end


%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalOpenEditor %%%
%%%%%%%%%%%%%%%%%%%%%%%
function LocalOpenEditor(hSrc,event,Editor)
% Properties menu callback (hSrc = menu handle)
cstprefs.sisoprops(Editor);
