function s = edit(Constr,Container)
%EDIT  Builds generic constraint editor. Should be overloaded by 
%      specific subclasses.

%   Authors: P. Gahinet, A.Stothert
%   Copyright 1986-2004 The MathWorks, Inc. 
%   $Revision: 1.1.6.2 $ $Date: 2004/12/26 21:51:25 $

import com.mathworks.mwt.*;

% Definitions
Prefs = cstprefs.tbxprefs;
GL_31 = java.awt.GridLayout(3,1,0,3);
LEFT  = MWLabel.LEFT;
CENTER = MWLabel.CENTER;
BWEST = MWBorderLayout.WEST;
BCENTER = MWBorderLayout.CENTER;
BEAST = MWBorderLayout.EAST;

% Labels
P1 = MWPanel(GL_31); 
Container.add(P1,BWEST);
L = cell(3,1);
Text = {'Select edge to edit';'xCoord';'yCoord'};
for ct=1:numel(L)
    Label = MWLabel(sprintf('%s:',Text{ct}),LEFT); 
    P1.add(Label);  
    Label.setFont(Prefs.JavaFontP);
    L{ct} = Label;
end

%Edge Selector
EdgeP  = MWPanel(GL_31);
EdgeCB = MWChoice;
for ct = 1:size(Constr.xCoords,1)
   EdgeCB.addItem(num2str(ct));
end
EdgeP.add(EdgeCB);

% Text fields
P6 = MWPanel(MWBorderLayout(0,0));
Container.add(P6,BCENTER);
P2 = MWPanel(MWBorderLayout(7,0)); 
P6.add(P2,BWEST);
T = cell(3,3);
% Column #1
P3 = MWPanel(GL_31);  P2.add(P3,BWEST);
P3.add(EdgeCB);   T{1,1} = EdgeCB;
W = MWTextField(10); 
P3.add(W);   W.setFont(Prefs.JavaFontP);  T{2,1} = W;
W = MWTextField(10); 
P3.add(W);   W.setFont(Prefs.JavaFontP);  T{3,1} = W;
% Column #2
P4 = MWPanel(GL_31);   P2.add(P4,BCENTER);
P4.add(MWLabel('',LEFT));
W = MWLabel(sprintf('%s','to'),CENTER); 
P4.add(W);   W.setFont(Prefs.JavaFontP);  T{2,2} = W;
W = MWLabel(sprintf('%s','to'),CENTER); 
P4.add(W);   W.setFont(Prefs.JavaFontP);  T{3,2} = W;
% Column #3
P5 = MWPanel(GL_31);   P2.add(P5,BEAST);
P5.add(MWLabel('',LEFT));
W = MWTextField(10); 
P5.add(W);   W.setFont(Prefs.JavaFontP);  T{2,3} = W;
W = MWTextField(10); 
P5.add(W);   W.setFont(Prefs.JavaFontP);  T{3,3} = W;

% Callbacks
Callback = {@LocalChangeEdge Constr T};
set(T{1,1},'ItemStateChangedCallback',Callback)
Callback = {@LocalEditCoord Constr T 1 'xCoord'};
set(T{2,1},'ActionPerformedCallback',Callback,'FocusLostCallback',Callback)
Callback = {@LocalEditCoord Constr T 1 'yCoord'};
set(T{3,1},'ActionPerformedCallback',Callback,'FocusLostCallback',Callback)
Callback = {@LocalEditCoord Constr T 2 'xCoord'};
set(T{2,3},'ActionPerformedCallback',Callback,'FocusLostCallback',Callback)
Callback = {@LocalEditCoord Constr T 2 'yCoord'};
set(T{3,3},'ActionPerformedCallback',Callback,'FocusLostCallback',Callback)

% Initialize text field values
LocalUpdateText([],[],Constr,T);

% Update listeners (track changes in constraint data)
props = [Constr.findprop('xCoord');...
      Constr.findprop('yCoord');...
      Constr.findprop('xUnits');...
      Constr.findprop('yUnits'); ...
      Constr.findprop('SelectedEdge')];
Listener = handle.listener(Constr,props,'PropertyPostSet',{@LocalUpdateText Constr T});
Listener = [Listener; ...
   handle.listener(Constr,'DataChanged',{@LocalUpdateText Constr T})];

% Save other handles
s = struct('Panels',{{P1;P2;P3;P4;P5;P6}},'Handles',{[L ; T(:)]},'Listeners',Listener);

%--------------------------------------------------------------------------
function LocalChangeEdge(eventsrc,eventdata,Constr,T)

NewEdge = str2double(T{1,1}.getSelectedItem);
if (NewEdge~=Constr.SelectedEdge) && ...
      (NewEdge > 0) && ...
      (NewEdge <= size(Constr.xCoords,1)) 
   Constr.SelectedEdge = NewEdge;
   LocalUpdateText([],[],Constr,T);
end

%--------------------------------------------------------------------------
function LocalUpdateText(eventsrc,eventdata,Constr,T)

% Updates text fields from contraint data
x = unitconv(Constr.xCoords(Constr.SelectedEdge,:),Constr.xUnits,Constr.getDisplayUnits('XUnits'));
y = unitconv(Constr.yCoords(Constr.SelectedEdge,:),Constr.yUnits,Constr.getDisplayUnits('YUnits'));
if T{1,1}.getItemCount ~= size(Constr.xCoords,1)
   %Added or deleted edge, need to reset combobox item list
   Callback = get(T{1,1},'ItemStateChangedCallback');
   %Disable combobox callbacks
   set(T{1,1},'ItemStateChangedCallback','')
   T{1,1}.removeAll;
   for ct = 1:size(Constr.xCoords,1)
      T{1,1}.addItem(num2str(ct));
   end
   T{1,1}.select(Constr.SelectedEdge(1)-1);
   set(T{1,1},'ItemStateChangedCallback',Callback)
else
   T{1,1}.select(Constr.SelectedEdge(1)-1);
end
set(T{2,1},'Text',sprintf('%.3g',x(1)))
set(T{2,3},'Text',sprintf('%.3g',x(2)))
set(T{3,1},'Text',sprintf('%.3g',y(1)))
set(T{3,3},'Text',sprintf('%.3g',y(2)))


%--------------------------------------------------------------------------
function v = LocalEvaluate(TextField)
% Evaluate text field content
s = get(TextField,'Text');
if isempty(s)
   v = [];
else
   v = evalin('base',s,'[]');
   if ~isequal(size(v),[1 1]) || ~isreal(v),
      v = [];
   end
end

%--------------------------------------------------------------------------
function LocalEditCoord(TextField,eventData,Constr,T,jx,WhichCoord)

%Find axes units
switch WhichCoord
   case 'xCoords'
      Units = 'xUnits';
   case 'yCoords'
      Units = 'yUnits';
end

% Update x or y coord
v = unitconv(LocalEvaluate(TextField),...
   Constr.getDisplayUnits(Units), ...
   Constr.(Units)(Constr.SelectedEdge));

% Get new range 
Range = Constr.(WhichCoord)(Constr.SelectedEdge,:);
if ~isempty(v)
   Range(jx) = v;
end

% Update data
if isequal(Constr.(WhichCoord),Range)
   % No change: resync text
   LocalUpdateText([],[],Constr,T);
else
   T = Constr.recordon;
   Constr.(WhichCoord)(Constr.SelectedEdge,:) = Range;
   Constr.recordoff(T);
   % Update display and notify observers
   Constr.send('DataChangeFinished');
   update(Constr)
end
