function Main = char_gui(PropObj)
%CHAR_GUI  GUI for editing characteristic properties of PropObj

%   Author(s): A. DiVergilio
%   Copyright 1986-2000 The MathWorks, Inc. 
%   $Revision: 1.6 $  $Date: 2000/08/02 16:05:48 $

%---Get Toolbox Preferences
Prefs = cstprefs.tbxprefs;

%---Definitions
WEST   = com.mathworks.mwt.MWBorderLayout.WEST;
CENTER = com.mathworks.mwt.MWBorderLayout.CENTER;
FL_L50 = java.awt.FlowLayout(java.awt.FlowLayout.LEFT,5,0);

%---Top-level panel (MWGroupbox)
Main = com.mathworks.mwt.MWGroupbox(sprintf('Response Characteristics'));
Main.setLayout(com.mathworks.mwt.MWBorderLayout(0,0));
Main.setFont(Prefs.JavaFontB);

%---For case of no characteristics to set, display the following string
s.NullString = com.mathworks.mwt.MWLabel(sprintf('(no characteristics available for selected response plot)'));
s.NullString.setFont(Prefs.JavaFontP);
Main.add(s.NullString,com.mathworks.mwt.MWBorderLayout.NORTH);

%---Response Characteristics panel
s.RC = com.mathworks.mwt.MWPanel(java.awt.GridLayout(6,1,0,4));
Main.add(s.RC,com.mathworks.mwt.MWBorderLayout.WEST);

%---PeakResponse
s.R1 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R1);
s.PeakResponse = com.mathworks.mwt.MWCheckbox(sprintf('Show peak response')); s.R1.add(s.PeakResponse,WEST);
s.PeakResponse.setFont(Prefs.JavaFontP);

%---SettlingTime
s.R2 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R2);
s.SettlingTime = com.mathworks.mwt.MWCheckbox(sprintf('Show settling time within')); s.R2.add(s.SettlingTime,WEST);
s.SettlingTime.setFont(Prefs.JavaFontP);
   %---SettlingTimeThreshold
   s.R2E = com.mathworks.mwt.MWPanel(FL_L50); s.R2.add(s.R2E,CENTER);
   s.SettlingTimeThreshold = com.mathworks.mwt.MWTextField(3); s.R2E.add(s.SettlingTimeThreshold);
   s.SettlingTimeThreshold.setFont(Prefs.JavaFontP);
   s.R2EL1 = com.mathworks.mwt.MWLabel(sprintf('%%')); s.R2E.add(s.R2EL1);
   s.R2EL1.setFont(Prefs.JavaFontP);

%---RiseTime
s.R3 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R3);
s.RiseTime = com.mathworks.mwt.MWCheckbox(sprintf('Show rise time from')); s.R3.add(s.RiseTime,WEST);
s.RiseTime.setFont(Prefs.JavaFontP);
   %---RiseTimeLimits
   s.R3E = com.mathworks.mwt.MWPanel(FL_L50); s.R3.add(s.R3E,CENTER);
   s.RiseTimeLimits1 = com.mathworks.mwt.MWTextField(3); s.R3E.add(s.RiseTimeLimits1);
   s.RiseTimeLimits1.setFont(Prefs.JavaFontP);
   s.R3EL1 = com.mathworks.mwt.MWLabel(sprintf('to')); s.R3E.add(s.R3EL1);
   s.R3EL1.setFont(Prefs.JavaFontP);
   s.RiseTimeLimits2 = com.mathworks.mwt.MWTextField(3); s.R3E.add(s.RiseTimeLimits2);
   s.RiseTimeLimits2.setFont(Prefs.JavaFontP);
   s.R3EL2 = com.mathworks.mwt.MWLabel(sprintf('%%')); s.R3E.add(s.R3EL2);
   s.R3EL2.setFont(Prefs.JavaFontP);

%---SteadyState
s.R4 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R4);
s.SteadyState = com.mathworks.mwt.MWCheckbox(sprintf('Show steady state')); s.R4.add(s.SteadyState,WEST);
s.SteadyState.setFont(Prefs.JavaFontP);

%---Stability Margin
s.R5 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R5);
s.StabilityMargin = com.mathworks.mwt.MWCheckbox(sprintf('Show minimum stability margins')); s.R5.add(s.StabilityMargin,WEST);
s.StabilityMargin.setFont(Prefs.JavaFontP);

%---All Crossover Frequencies
s.R6 = com.mathworks.mwt.MWPanel(com.mathworks.mwt.MWBorderLayout(0,0)); s.RC.add(s.R6);
s.AllStabilityMargin = com.mathworks.mwt.MWCheckbox(sprintf('Show all stability margins')); s.R6.add(s.AllStabilityMargin,WEST);
s.AllStabilityMargin.setFont(Prefs.JavaFontP);

%---Install PropObj listeners and GUI callbacks
cstP = findpackage('cstprefs');
resppropC = cstP.findclass('respprop');
EventType = 'PropertyPostSet';
PointOfAttachment = PropObj;
Callback = {@localReadProp,s};
GUICallback = {@localWriteProp,PropObj};
   %---PeakResponse
    EventSrc = resppropC.findprop('PeakResponse');
    s.PeakResponseListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.PeakResponse,'Name','PeakResponse','ItemStateChangedCallback',GUICallback);
   %---SettlingTime
    EventSrc = resppropC.findprop('SettlingTime');
    s.SettlingTimeListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.SettlingTime,'Name','SettlingTime','ItemStateChangedCallback',GUICallback);
   %---SettlingTimeThreshold
    EventSrc = resppropC.findprop('SettlingTimeThreshold');
    s.SettlingTimeThresholdListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.SettlingTimeThreshold,'Name','SettlingTimeThreshold',...
       'ActionPerformedCallback',GUICallback,'FocusLostCallback',GUICallback);
   %---RiseTime
    EventSrc = resppropC.findprop('RiseTime');
    s.RiseTimeListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.RiseTime,'Name','RiseTime','ItemStateChangedCallback',GUICallback);
   %---RiseTimeLimits
    EventSrc = resppropC.findprop('RiseTimeLimits');
    s.RiseTimeLimitsListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.RiseTimeLimits1,'Name','RiseTimeLimits1',...
       'ActionPerformedCallback',GUICallback,'FocusLostCallback',GUICallback);
    set(s.RiseTimeLimits2,'Name','RiseTimeLimits2',...
       'ActionPerformedCallback',GUICallback,'FocusLostCallback',GUICallback);
   %---SteadyState
    EventSrc = resppropC.findprop('SteadyState');
    s.SteadyStateListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.SteadyState,'Name','SteadyState','ItemStateChangedCallback',GUICallback);
   %---StabilityMargin
    EventSrc = resppropC.findprop('StabilityMargin');
    s.StabilityMarginsListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.StabilityMargin,'Name','StabilityMargin','ItemStateChangedCallback',GUICallback);
   %---AllStabilityMargin
    EventSrc = resppropC.findprop('AllStabilityMargin');
    s.AllStabilityMarginsListener = handle.listener(PointOfAttachment,EventSrc,EventType,Callback);
    set(s.AllStabilityMargin,'Name','AllStabilityMargin','ItemStateChangedCallback',GUICallback);

%---Store java handles
set(Main,'UserData',s);


%%%%%%%%%%%%%%%%%
% localReadProp %
%%%%%%%%%%%%%%%%%
function localReadProp(eventSrc,eventData,s)
% Update GUI when property object changes
if eventData.AffectedObject.ListenerEnable
   Name = eventSrc.Name;
   NewValue = eventData.NewValue;
   %---Set GUI state/text
   switch Name
   case 'PeakResponse'
      if isempty(NewValue)
         s.RC.remove(s.R1);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R1.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R1);
         end
         s.PeakResponse.setState(strcmpi(NewValue,'on'));
      end
   case 'SettlingTime'
      if isempty(NewValue)
         s.RC.remove(s.R2);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R2.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R2);
         end
         s.SettlingTime.setState(strcmpi(NewValue,'on'));
      end
   case 'SettlingTimeThreshold'
      s.SettlingTimeThreshold.setText(num2str(NewValue*100));
   case 'RiseTime'
      if isempty(NewValue)
         s.RC.remove(s.R3);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R3.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R3);
         end
         s.RiseTime.setState(strcmpi(NewValue,'on'));
      end
   case 'RiseTimeLimits'
      if isempty(NewValue)
         s.RiseTimeLimits1.setText(sprintf(''));
         s.RiseTimeLimits2.setText(sprintf(''));
      else
         s.RiseTimeLimits1.setText(num2str(NewValue(1)*100));
         s.RiseTimeLimits2.setText(num2str(NewValue(2)*100));
      end
   case 'SteadyState'
      if isempty(NewValue)
         s.RC.remove(s.R4);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R4.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R4);
         end
         s.SteadyState.setState(strcmpi(NewValue,'on'));
      end
   case 'StabilityMargin'
      if isempty(NewValue)
         s.RC.remove(s.R5);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R5.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R5);
         end
         s.StabilityMargin.setState(strcmpi(NewValue,'on'));
      end
   case 'AllStabilityMargin'
      if isempty(NewValue)
         s.RC.remove(s.R6);
         n = s.RC.getComponentCount;
         s.RC.setLayout(java.awt.GridLayout(n,1,0,4));
      else
         if isempty(s.R6.getParent)
            n = s.RC.getComponentCount;
            s.RC.setLayout(java.awt.GridLayout(n+1,1,0,4));
            s.RC.add(s.R6);
         end
         s.AllStabilityMargin.setState(strcmpi(NewValue,'on'));
      end
   end
   %---Display string if no characteristics are available
   if s.RC.getComponentCount==0
      s.NullString.setVisible(1);
   else
      s.NullString.setVisible(0);
   end
end


%%%%%%%%%%%%%%%%%%
% localWriteProp %
%%%%%%%%%%%%%%%%%%
function localWriteProp(eventSrc,eventData,PropObj)
% Update property object when GUI changes
PropObj.ListenerEnable = 1;  %---Keep PropObj listeners enabled !!!
Name = get(eventSrc,'Name');
switch Name
case 'SettlingTimeThreshold'
   oldval = PropObj.SettlingTimeThreshold;
   if ~isempty(oldval)  %---In case response plot was changed while textfield had focus
      val = evalnum(get(eventSrc,'Text'))/100;
      if isequal(oldval,val)  
         %---No change: return
         return;
      elseif isempty(val)
         %---Invalid number: revert to original value
         set(eventSrc,'Text',num2str(oldval*100));
         return;
      else
         val = max(min(val,1),0);
         set(eventSrc,'Text',num2str(val*100));
         PropObj.SettlingTimeThreshold = val;
         PropObj.LastChange = 'SettlingTimeThreshold';
      end
   end
case {'RiseTimeLimits1','RiseTimeLimits2'}
   oldvec = PropObj.RiseTimeLimits;
   if ~isempty(oldvec)  %---In case response plot was changed while textfield had focus
      if strcmpi(Name,'RiseTimeLimits1')
         oldval = oldvec(1);
      else
         oldval = oldvec(2);
      end
      val = evalnum(get(eventSrc,'Text'))/100;
      if isequal(oldval,val)
         %---No change: return
         return;
      elseif isempty(val)
         %---Invalid number: revert to original value
         set(eventSrc,'Text',num2str(oldval*100));
         return;
      else
         %---Limit to (0,1)
         val = max(min(val,1),0);
         if strcmpi(Name,'RiseTimeLimits1')
            if val<oldvec(2)
               PropObj.RiseTimeLimits = [val oldvec(2)];
            elseif val<1
               PropObj.RiseTimeLimits = [val 1];
            else
               %---Invalid number, revert to original value
               set(eventSrc,'Text',num2str(oldval*100));
            end
         else
            if val>oldvec(1)
               PropObj.RiseTimeLimits = [oldvec(1) val];
            elseif val>0
               PropObj.RiseTimeLimits = [0 val];
            else
               %---Invalid number, revert to original value
               set(eventSrc,'Text',num2str(oldval*100));
            end
         end
         PropObj.LastChange = 'RiseTimeLimits';
      end
   end
otherwise
   set(PropObj,Name,get(eventSrc,'State'));
   PropObj.LastChange = Name;
end


%%%%%%%%%%%
% evalnum %
%%%%%%%%%%%
function val = evalnum(val)
% Evaluate string val, returning valid real scalar only, empty otherwise
if ~isempty(val)
   val = evalin('base',val,'[]');
   if ~isnumeric(val) | ~(isreal(val) & isfinite(val) & isequal(size(val),[1 1]))
      val = [];
   end
end
