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(); } }