import java.awt.*;
import java.awt.event.*;
import java.io.*;
/**
* A class which contains displays and controls related either to the input of
* axis distances and traces of generators or to the combinatorial
* decomposition of the trace plane.
*
* @author Jonathan A. Poritz
* @version 1.7, 17 Sep 1998
*/
public class InputPanel extends Panel {
/**
* A panel containing controls and displays related to the axis distance.
*/
Panel distlinegroup;
/**
* Clicking this button resets to default the portion of the axis distance
* line which is visible.
*/
Button distreset;
/**
* A container for the zoom in and out buttons on the axis distance display.
*/
Panel distzooms;
/**
* Clicking this button zooms in by a factor of two on the axis distance
* display.
*/
Button distzoomin;
/**
* Clicking this button zooms out by a factor of two on the axis distance
* display.
*/
Button distzoomout;
/**
* A panel for the graphical display/entry of the axis distance input.
*/
DistLinePanel distlinepanel;
/**
* A Label for the axis distance IO field.
*/
Label distvaluelabel;
/**
* The axis distance IO field.
*/
TextField distvaluetext;
/**
* A panel containing controls and displays related to the trace plain and
* the currently selected trace and its corresponding domain combinatorics.
*/
Panel traceplanegroup;
/**
* A panel that contains the trace plane zoom in, zoom out, reset and
* decompose buttons.
*/
Panel tracebuttongroup;
/**
* Clicking this button resets to default the portion of the trace plane
* which is visible.
*/
Button tracereset;
/**
* Clicking this button zooms in by a factor of two on the trace plane
* display.
*/
Button tracezoomin;
/**
* Clicking this button zooms out by a factor of two on the trace plane
* display.
*/
Button tracezoomout;
/**
* Clicking this button gives a complete decomposition by the combinatorial
* type of the corresponding fundamental domain of the visible portion of
* the trace plane.
*/
Button tracedecompose;
/**
* A panel for the graphical display/entry of the trace.
*/
TracePlanePanel traceplanepanel;
/**
* A label declaring the portion of the trace plane which is currently
* visible.
*/
Label traceplanelabel;
/**
* A panel with a label and field for IO of the current trace.
*/
Panel tracevaluepanel;
/**
* A label for the trace IO field.
*/
Label tracevaluelabel;
/**
* The trace IO field.
*/
TextField tracevaluetext;
/**
* A label which shows the combinatorics of the fundamental domain
* corresponding to the currently selected trace.
*/
Label currdomaincomblabel;
/**
* A prefix string for the current domain combinatorics label.
*/
public static final String CURRDOMCOMBLABEL="This domain of type ";
/**
* A label which provides a running progress estimate during the computation
* of the trace place decomposition.
*/
Label decomposeprogress;
/**
* An object for laying out panels with the GrigBag layout manager.
*/
GridBagLayout gridbag;
/**
* A constraint object for the GrigBag laying out of panels.
*/
GridBagConstraints constraints;
/**
* An insets object for the GridBag laying out of panels.
*/
Insets insets;
/**
* A reference to the applet's outputpanel.
*
* @see FDBApplet#outputpanel
*/
OutputPanel outputpanel;
/**
* The currently selected trace.
*/
protected Complex trace = new Complex(0D,1D);
/**
* The (1,1) entry of the element cannonically associated with the current
* trace.
*/
protected Complex z11 = new Complex(0D,0D);
/**
* The currently selected axis distance.
*/
protected double dist = 1D;
/**
* The maxpow calculated for a Ford domain with the current trace -- not
* necessarily valid for a Dirichlet domain with the same trace, but used
* nonetheless.
*/
protected int calcmaxpow;
/**
* The domain combinatorics for the currently selected domain type, trace and
* axis distance.
*/
protected DomainCombinatorics currdomaincomb;
/**
* Constructor for InputPanels.
*
* @param tptpnl the applet's outputpanel.
*/
public InputPanel(OutputPanel tptpnl) {
// store the reference to the applet's outputpanel and make it refer
// to this inputpanel
outputpanel = tptpnl;
outputpanel.inputpanel = this;
// create objects for GridBag laying out
gridbag = new GridBagLayout();
constraints = new GridBagConstraints();
insets = new Insets(0,0,0,0);
// construct the objects of the distlinegroup
distzoomin = new Button("+");
// deal with associated events
distzoomin.addActionListener(new ActionListener () {
// zoom in the distlinepanel
public void actionPerformed(ActionEvent e) {
distlinepanel.zoom(.5D);
}
});
distzoomout = new Button("-");
// deal with associated events
distzoomout.addActionListener(new ActionListener () {
// zoom out the distlinepanel
public void actionPerformed(ActionEvent e) {
distlinepanel.zoom(2D);
}
});
distzooms = new Panel();
distreset = new Button("Reset");
// deal with associated events
distreset.addActionListener(new ActionListener () {
// reset the distlinepanel
public void actionPerformed(ActionEvent e) {
distlinepanel.reset();
}
});
distvaluelabel = new Label("Dist. to axis: ");
distvaluelabel.setAlignment(Label.CENTER);
distvaluetext = new TextField(7);
// deal with associated events
distvaluetext.addActionListener(new ActionListener () {
// user has entered an axis distance by hand
public void actionPerformed(ActionEvent e) {
double d;
try {
d = Double.valueOf(distvaluetext.getText()).doubleValue();
if (d < 0D)
d = -d;
} catch(NumberFormatException nfe) {
d = 1D;
}
if ((d != 0D) || (trace.y != 0D) || (Math.abs(trace.x) >= 2D)) {
// here we have a non-zero axis distance or zero distance and
// loxodromic or hyperbolic element (with non-zero translation
// distance) so we can accept this new axis dist, recompute and
// redraw
dist = d;
distlinepanel.repaint();
update();
}
else // zero axis dist and ellip or parabolic element, so use old dist
distvaluetext.setText(Complex.DoubleToString(dist, 5));
traceplanepanel.decomposed = false;
traceplanepanel.draw_axes = true;
traceplanepanel.repaint();
}
});
distlinepanel = new DistLinePanel(this);
distlinegroup = new Panel();
// lay out the objects of the distlinegroup
distzooms.setLayout(gridbag);
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.gridx = 0;
constraints.gridy = 0;
gridbag.setConstraints(distzoomin, constraints);
distzooms.add(distzoomin);
constraints.gridx = 1;
gridbag.setConstraints(distzoomout, constraints);
distzooms.add(distzoomout);
distlinegroup.setLayout(gridbag);
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.gridx = 0;
constraints.gridy = 0;
gridbag.setConstraints(distreset, constraints);
distlinegroup.add(distreset);
insets.bottom = 5;
constraints.insets = insets;
constraints.gridy = 1;
gridbag.setConstraints(distzooms, constraints);
distlinegroup.add(distzooms);
constraints.gridy = 2;
gridbag.setConstraints(distlinepanel, constraints);
distlinegroup.add(distlinepanel);
insets.bottom = 0;
constraints.gridy = 3;
gridbag.setConstraints(distvaluelabel, constraints);
distlinegroup.add(distvaluelabel);
constraints.gridy = 4;
gridbag.setConstraints(distvaluetext, constraints);
distlinegroup.add(distvaluetext);
// construct and lay out the objects of the traceplanegroup
tracevaluepanel = new Panel();
tracevaluelabel = new Label("Re,Im of trace: ");
tracevaluetext = new TextField(30);
// deal with associated events
tracevaluetext.addActionListener(new ActionListener () {
// user has entered a trace by hand
public void actionPerformed(ActionEvent e) {
// string conversion gives the complex number i in case of
// bad number format
Complex tr = Complex.stringToComplex(tracevaluetext.getText());
// make negative imaginary parts positive
if (tr.y < 0D)
tr.y = -tr.y;
if ((tr.y != 0D) || (Math.abs(tr.x) >= 2D) || (outputpanel.fordordirichlet.getSelectedIndex() == 0) || (dist != 0D)) {
// here we have a loxodromic or hyperbolic element (with non-zero
// translation distance) or a Ford domain or a Dirichlet domain with
// non-zero axis distance, so we can accept this new trace, recompute
// and redraw
trace = tr;
traceplanepanel.repaint();
update();
}
else // zero AD, Dir domain and ellip or para trace, so use old trace
tracevaluetext.setText(trace.toString());
}
});
tracevaluepanel.setLayout(new FlowLayout());
tracevaluepanel.add(tracevaluelabel);
tracevaluepanel.add(tracevaluetext);
tracebuttongroup = new Panel();
tracereset = new Button("Reset");
// deal with associated events
tracereset.addActionListener(new ActionListener () {
// reset trace plane window and discard any traceplane decomposition
public void actionPerformed(ActionEvent e) {
traceplanepanel.decomposed = false;
traceplanepanel.draw_axes = true;
traceplanepanel.reset();
traceplanelabel.setText(traceplanepanel.toString());
}
});
tracezoomin = new Button("+");
// deal with associated events
tracezoomin.addActionListener(new ActionListener () {
// zoom in trace plane and discard any traceplane decomposition
public void actionPerformed(ActionEvent e) {
traceplanepanel.decomposed = false;
traceplanepanel.draw_axes = true;
traceplanepanel.zoom(.5D);
}
});
tracezoomout = new Button("-");
// deal with associated events
tracezoomout.addActionListener(new ActionListener () {
// zoom out trace plane and discard any traceplane decomposition
public void actionPerformed(ActionEvent e) {
traceplanepanel.decomposed = false;
traceplanepanel.draw_axes = true;
traceplanepanel.zoom(2D);
}
});
tracedecompose = new Button("Decompose");
// deal with associated events
tracedecompose.addActionListener(new ActionListener () {
// decompose the trace plane by combinatorial type
public void actionPerformed(ActionEvent e) {
// only decompose if the trace plane is currently undecomposed
if (!traceplanepanel.decomposed)
traceplanepanel.decompose();
}
});
tracebuttongroup.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
tracebuttongroup.add(tracereset);
tracebuttongroup.add(tracezoomin);
tracebuttongroup.add(tracezoomout);
tracebuttongroup.add(tracedecompose);
traceplanegroup = new Panel();
traceplanelabel = new Label();
currdomaincomblabel = new Label();
traceplanepanel = new TracePlanePanel(this);
traceplanelabel.setAlignment(Label.CENTER);
currdomaincomblabel.setAlignment(Label.CENTER);
decomposeprogress = new Label();
decomposeprogress.setAlignment(Label.CENTER);
traceplanegroup.setLayout(gridbag);
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.gridx = 0;
constraints.gridy = 0;
insets.bottom = 5;
constraints.insets = insets;
gridbag.setConstraints(tracebuttongroup, constraints);
traceplanegroup.add(tracebuttongroup);
constraints.gridy = 1;
gridbag.setConstraints(traceplanepanel, constraints);
traceplanegroup.add(traceplanepanel);
insets.bottom = 0;
constraints.gridy = 2;
constraints.fill = GridBagConstraints.HORIZONTAL;
gridbag.setConstraints(traceplanelabel, constraints);
traceplanegroup.add(traceplanelabel);
constraints.gridy = 3;
gridbag.setConstraints(tracevaluepanel, constraints);
traceplanegroup.add(tracevaluepanel);
constraints.gridy = 4;
gridbag.setConstraints(currdomaincomblabel, constraints);
traceplanegroup.add(currdomaincomblabel);
constraints.gridy = 5;
gridbag.setConstraints(decomposeprogress, constraints);
traceplanegroup.add(decomposeprogress);
// put together the entire inputpanel with FlowLayout
this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
this.add(distlinegroup);
this.add(traceplanegroup);
// compute values and draw the inputpanel for the first time
update();
}
/**
* Recomputes and redraws both the input and output panels.
*/
public void update() {
// recompute z11, maxpow, current domain combinatorics and redisplay
// on input side
z11 = Complex.make_z11(trace);
calcmaxpow = Complex.make_maxpow(trace, z11);
currdomaincomb = new DomainCombinatorics(trace, dist, outputpanel.fordordirichlet.getSelectedIndex(), z11, (outputpanel.boundarypanel.usecalcmaxpow ? calcmaxpow : outputpanel.boundarypanel.chosenmaxpow));
currdomaincomblabel.setText(CURRDOMCOMBLABEL+currdomaincomb.makeLabel());
distvaluetext.setText(Complex.DoubleToString(dist, 5));
tracevaluetext.setText(trace.toString());
repaint();
// transfer computed results to outputpanel and redisplay it
outputpanel.boundarypanel.calcmaxpow = calcmaxpow;
outputpanel.boundarypanel.dist = dist;
outputpanel.boundarypanel.z11.x = z11.x;
outputpanel.boundarypanel.z11.y = z11.y;
outputpanel.maxpowlabel.setText("Maxpow is "+calcmaxpow+"... ");
outputpanel.boundarypanel.update();
}
}