/* * @(#)MoleculeEditor_1_0.java 96/05/28 Denis M. BAYADA * * Copyright (c) 1996 Denis M. BAYADA, University of Leeds, Leeds, U.K. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and * without fee is hereby granted. * Please email denis@mi.leeds.ac.uk for any questions or comments included * questions on commercial availability. * * This software is given "as is". I do not accept responsibility * for any damage to software or hardware that it may cause. */ import java.awt.*; import java.applet.*; import java.lang.Math; /* * The main class. This class is static. It contains all the interface. */ public class MoleculeEditor_1_0 extends java.applet.Applet { // These static final byte constants are used to check what // is the current mode static final byte SINGLE = 1; // Single bond drawing static final byte DOUBLE = 2; // Double bond drawing static final byte SELECT = 3; // Selection static final byte LASSO = 5; // Lasso static final byte CYCLO6 = 4; // cyclohexane drawing static final byte CHANGEAT = 6; // Changing Atom Type static final byte ZOOM = 7; // Zoom static final byte ARO6 = 8; // Aromatic 6 static final byte TRIPLE = 9; // Triple bond drawing static final byte UNKNOWN = 10; // unknown selection (should never happen) static final byte ARO5 = 11; // Aromatic 5 static final byte CYCLO5 = 12; // cyclopentane // Different GUI components Panel drawing_area; // Where the molecule is drawn Button draw_single_button, change_atom_type_button; // The buttons Button draw_double_button, lasso_button, select_button; Button delete_selected_button, zoom_button, draw_triple_button; Button merge_button; Panel button_panel; // Panel that contains the buttons Label global_name; // The Molecule Editor label Label version_name; // The version label Label atom_type; // The atom type changing label Choice choice; // The atom type menu ImageLinesButton_1_0 cyclo6, aro6, cyclo5, aro5; // The drawn buttons static String cyclo6Name = new String("Cyclo6"); // name of drawn buttons static String aro6Name = new String("Aro6"); static String cyclo5Name = new String("Cyclo5"); static String aro5Name = new String("Aro5"); TextField message_window = new TextField(17); // The message window GridBagLayout gridbag = new GridBagLayout(); // The container layout // The rest Molecule_1_0 aMolecule; // The molecule itself static int current_selected = SELECT; // The variable that is set when // a button is clicked. // It is a static! int x,y,oldx,oldy,start_atom; // variables that store the mouse position // when a button is clicked, the previous // mouse position, the atom on which // the mouse was clicked. int atom_highlighted = -1; // The atom id that is covered by the mouse int bond_highlighted = -1; // the bond id that is covered by the mouse Polygon lasso_pol; // The polygon that stores the lasso int temp_int=0; // temporary variables int temp_x[] = new int[20]; // temporary variables int temp_y[] = new int[20]; // temporary variables int spare_x[] = new int[100]; // variables used for the ZOOM int spare_y[] = new int[100]; // variables used for the ZOOM int gravity_x, gravity_y; // variables used for the ZOOM int runner; // variables used for the ZOOM int last_selected = -1; // variables used for the Selection boolean inside_drawing_area = false; // true if mouse in drawing area // init function is called once. It draws the whole interface public void init() { Polygon pol; // Creation of the cyclo6 drawn button: int angle = 0; for (int i=0; i<6; i++) { temp_x[i] = (int)(15.0*Math.cos(60.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(15.0*Math.sin(60.0*(double)angle/180.0*Math.PI))+15; angle++; } pol = new Polygon(temp_x,temp_y,6); cyclo6 = new ImageLinesButton_1_0(pol,cyclo6Name); // Creation of the aro6 drawn button: temp_x[0] = 30; temp_y[0] = 15; temp_x[11] = temp_x[0]; temp_y[11] = temp_y[0]; angle = 1; for (int i=1; i<11; i+=2) { temp_x[i] = (int)(15.0*Math.cos(60.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(15.0*Math.sin(60.0*(double)angle/180.0*Math.PI))+15; angle++; temp_x[i+1] = temp_x[i]; temp_y[i+1] = temp_y[i]; } angle = 0; for (int i=12; i<18; i++) { temp_x[i] = (int)(10.0*Math.cos(60.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(10.0*Math.sin(60.0*(double)angle/180.0*Math.PI))+15; angle++; } aro6 = new ImageLinesButton_1_0(18, temp_x, temp_y, aro6Name); // Creation of the cyclo5 drawn button: angle = 0; for (int i=0; i<5; i++) { temp_x[i] = (int)(15.0*Math.cos(72.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(15.0*Math.sin(72.0*(double)angle/180.0*Math.PI))+15; angle++; } pol = new Polygon(temp_x,temp_y,5); cyclo5 = new ImageLinesButton_1_0(pol,cyclo5Name); // Creation of the aro5 drawn button: temp_x[0] = 30; temp_y[0] = 15; temp_x[9] = temp_x[0]; temp_y[9] = temp_y[0]; angle = 1; for (int i=1; i<9; i+=2) { temp_x[i] = (int)(15.0*Math.cos(72.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(15.0*Math.sin(72.0*(double)angle/180.0*Math.PI))+15; angle++; temp_x[i+1] = temp_x[i]; temp_y[i+1] = temp_y[i]; } angle = 0; for (int i=10; i<14; i++) { temp_x[i] = (int)(10.0*Math.cos(72.0*(double)angle/180.0*Math.PI))+15; temp_y[i] = (int)(10.0*Math.sin(72.0*(double)angle/180.0*Math.PI))+15; angle++; } aro5 = new ImageLinesButton_1_0(14, temp_x, temp_y, aro5Name); // simple text buttons draw_single_button = new Button("Single Bond"); draw_double_button = new Button("Double Bond"); draw_triple_button = new Button("Triple Bond"); change_atom_type_button = new Button("Atom Type"); lasso_button = new Button("Lasso"); select_button = new Button("Select"); zoom_button = new Button("Zoom"); merge_button = new Button("Merge Selected"); delete_selected_button = new Button("Delete Selected"); // Molecule Editor Label, drawn in Helvetica, bold, 26 Font font = new Font("Helvetica",Font.BOLD,26); global_name = new Label("Molecule Editor",Label.CENTER); global_name.setFont(font); // Version Label, drawn in Helvetica, plain, 12 font = new Font("Helvetica",Font.PLAIN,12); version_name = new Label("1.0",Label.CENTER); version_name.setFont(font); // atom type label atom_type = new Label("Change Selected to:",Label.CENTER); // Atom type menu choice = new Choice(); choice.addItem("C"); choice.addItem("B"); choice.addItem("N"); choice.addItem("O"); choice.addItem("F"); choice.addItem("Na"); choice.addItem("Mg"); choice.addItem("Si"); choice.addItem("P"); choice.addItem("S"); choice.addItem("Cl"); choice.addItem("K"); choice.addItem("Ca"); choice.addItem("Mn"); choice.addItem("Fe"); choice.addItem("Br"); choice.addItem("I"); choice.addItem("?"); // The storage panel for buttons // It is stored in a matrix of two columns and 10 rows // All the text buttons span 2 rows whereas drawn buttons are in on row button_panel = new Panel(); button_panel.setLayout(gridbag); constrain(button_panel, draw_single_button, 0,0,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,0,5); constrain(button_panel, draw_double_button, 0,1,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,0,5); constrain(button_panel, draw_triple_button, 0,2,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,0,5); constrain(button_panel, lasso_button, 0,3,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,0,5); constrain(button_panel, select_button, 0,4,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, zoom_button, 0,5,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, delete_selected_button, 0,6,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, merge_button, 0,7,2,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, cyclo6, 0,8,1,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, aro6, 1,8,1,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, cyclo5, 0,9,1,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); constrain(button_panel, aro5, 1,9,1,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 0.0,0.0, 5,5,5,5); // The rest of the interface drawing_area = new Panel(); // The molecule drawing area drawing_area.setLayout(new BorderLayout()); aMolecule = new Molecule_1_0(); // Creation of the molecule instance drawing_area.add("Center",aMolecule); // The molecule is put in its this.setLayout(gridbag); // drawing area message_window.setEditable(false); // Message window is set not editable // The interface is set up. It is a variable width/height grid of // 3 rows and 4 columns. It is used like this: // ___1___||____2____||___3___||____4____|| // 1| molecule_editor_label version // 2| msg_window at_label menu // 3| buttons molecule_drawing_area // constrain(this, global_name, 0,0,3,1,GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,1.0,0.0, 5,5,5,5); constrain(this, version_name, 3,0,1,1,GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER,1.0,0.0, 5,5,5,5); constrain(this, message_window, 0,1,2,1,GridBagConstraints.NONE, GridBagConstraints.WEST,0.0,0.0, 5,5,5,5); constrain(this, atom_type, 2,1,1,1,GridBagConstraints.NONE, GridBagConstraints.EAST,0.0,0.0, 5,5,5,5); constrain(this, choice, 3,1,1,1,GridBagConstraints.NONE, GridBagConstraints.WEST,0.0,0.0, 5,5,5,5); constrain(this, button_panel, 0,2,1,1,GridBagConstraints.NONE, GridBagConstraints.NORTHEAST,0.0,0.0, 5,5,5,5); constrain(this, drawing_area, 1,2,3,1,GridBagConstraints.BOTH, GridBagConstraints.CENTER,1.0,1.0, 5,5,5,5); show(); } // static function called by the ImageLinesButton_1_0 class instances // the clicked on public static void buttonMouseUp(String buttonName) { if (buttonName.compareTo(cyclo6Name) == 0) { current_selected = CYCLO6; } else if (buttonName.compareTo(aro6Name) == 0) { current_selected = ARO6; } else if (buttonName.compareTo(aro5Name) == 0) { current_selected = ARO5; } else if (buttonName.compareTo(cyclo5Name) == 0) { current_selected = CYCLO5; } } // The Event Handling function. This function acts according to the user // inputs. It calls LocalmouseDown/Up/Move/Drag functions when it detects // a mouse event and calls the apropriate functions when a button is clicked. public boolean handleEvent(Event e) { switch (e.id) { case Event.ACTION_EVENT: if (e.target == draw_single_button) { current_selected = SINGLE; message_window.setText("Single Bond Drawing"); } else if (e.target == draw_double_button) { current_selected = DOUBLE; message_window.setText("Double Bond Drawing"); } else if (e.target == draw_triple_button) { current_selected = TRIPLE; message_window.setText("Triple Bond Drawing"); } else if (e.target == select_button) { current_selected = SELECT; message_window.setText("Selection Mode"); } else if (e.target == lasso_button) { current_selected = LASSO; message_window.setText("Lasso Mode"); } else if (e.target == choice) { current_selected = CHANGEAT; message_window.setText("Changing Atom Type"); aMolecule.ChangeAtomTypes((String)e.arg); aMolecule.paint(aMolecule.getGraphics()); } else if (e.target == zoom_button) { current_selected = ZOOM; message_window.setText("Zoom Mode"); } else if (e.target == delete_selected_button) { aMolecule.DeleteSelected(); current_selected = SELECT; message_window.setText("Selection Mode"); } else if (e.target == merge_button) { aMolecule.MergeSelected(); aMolecule.paint(aMolecule.getGraphics()); current_selected = SELECT; message_window.setText("Selection Mode"); } else current_selected = UNKNOWN; break; case Event.MOUSE_DOWN: LocalmouseDown(e,e.x,e.y); return false; case Event.MOUSE_MOVE: LocalmouseMove(e,e.x,e.y); return false; case Event.MOUSE_UP: LocalmouseUp(e,e.x,e.y); return false; case Event.MOUSE_DRAG: LocalmouseDrag(e,e.x,e.y); return false; default: break; } return true; } // Function called by handleEvent, that acts when the mouse is dragged public boolean LocalmouseDrag(Event e, int x, int y) { Rectangle r = drawing_area.bounds(); // Checks if the mouse is in if (x>r.x && xr.y && y -1) { aMolecule.redrawAtom(atom_highlighted); } if (id > -1) { aMolecule.redrawAtom(id,Color.blue); } } atom_highlighted = id; if (this.x < 0 || this.y < 0) break; if (temp_int1 < 0 || temp_int2 < 0) { g.setColor(Color.lightGray); g.drawLine(this.x,this.y,oldx,oldy); g.setColor(Color.black); break; } if (oldx > -1) { g.setColor(Color.lightGray); g.drawLine(this.x,this.y,oldx,oldy); g.setColor(Color.black); } if (id > -1) { if (start_atom > -1 && aMolecule.BondExist(start_atom,id) != -1) oldx = -1; else { oldx = aMolecule.atoms_x[id]; oldy = aMolecule.atoms_y[id]; g.drawLine(this.x,this.y, aMolecule.atoms_x[id], aMolecule.atoms_y[id]); } } else { oldx = temp_int1; oldy = temp_int2; g.drawLine(this.x,this.y,oldx,oldy); } break; case LASSO: // add the new point to the lasso and draw the // the latest line g.setColor(Color.yellow); g.drawLine(oldx,oldy,temp_int1,temp_int2); lasso_pol.addPoint(temp_int1,temp_int2); oldx = temp_int1; oldy = temp_int2; break; case ZOOM: // if first lasso drag, find the gravity centre. // Otherwise scale the whole thing. if (oldy == -1) { oldy = temp_int2; gravity_x = 0; gravity_y = 0; for (int i=0; i= r.width || tempo_int2 <= 0 || tempo_int2 >= r.width) break; } if (runner == aMolecule.nbAtoms) { for (runner=0; runner -1 && this.y > -1 && // if mouse outside the (current_selected == SINGLE || // the drawing area erase current_selected == DOUBLE)) // the line drawn previously { Graphics g = aMolecule.getGraphics(); g.setColor(Color.lightGray); g.drawLine(this.x,this.y,oldx,oldy); g.setColor(Color.black); } return true; }// end mouseDrag // Function called by handleEvent, that acts when the mouse is moved public boolean LocalmouseMove(Event e, int x, int y) { Rectangle r = drawing_area.bounds(); if (x>r.x && xr.y && y -1) aMolecule.redrawAtom(atom_highlighted); if (id > -1) aMolecule.redrawAtom(id,Color.blue); atom_highlighted = id; id = aMolecule.cursor_on_bond(temp_int1,temp_int2); if (bond_highlighted != -1) aMolecule.redrawBond(bond_highlighted); if (id != -1) aMolecule.redrawBond(id,Color.blue); bond_highlighted = id; } } else if (inside_drawing_area) // if outside drawing area for the first { // time, redraw molecule inside_drawing_area = false; aMolecule.paint(aMolecule.getGraphics()); } return true; }// end mouseMove // Function called by handleEvent, that acts when the mouse is clicked public boolean LocalmouseDown(Event e, int x, int y) { Rectangle r = drawing_area.bounds(); if (x>r.x && xr.y && y -1) // an atom was selected/deselected { this.x = aMolecule.atoms_x[id]; this.y = aMolecule.atoms_y[id]; aMolecule.select_deselect_atom(id); if (aMolecule.atoms_selected[id]) last_selected = id; else last_selected = -1; aMolecule.redrawAtom(id); } else { last_selected = -1; id = aMolecule.cursor_on_bond(temp_int1,temp_int2); if (id > -1) // a bond is selected/deselected { aMolecule.select_deselect_bond(id); aMolecule.redrawBond(id); } } break; case SINGLE: case DOUBLE: case TRIPLE: if (id > -1) // if an atom is clicked on, store the { // coordinates and its id this.x = aMolecule.atoms_x[id]; this.y = aMolecule.atoms_y[id]; start_atom = id; } else { this.x = temp_int1; this.y = temp_int2; start_atom = -1; } oldx = -1; oldy = -1; break; case LASSO: // initialise the lasso polygon lasso_pol = new Polygon(); lasso_pol.addPoint(temp_int1,temp_int2); oldx = temp_int1; oldy = temp_int2; break; case ZOOM: // initialise the zoom oldy = -1; break; case CYCLO6: // redraw the polygon from a possible existing case ARO6: // atom aMolecule.paint(aMolecule.getGraphics()); Polygon pol = new Polygon(); pol.addPoint(temp_int1, temp_int2); pol.addPoint(temp_int1, temp_int2+59); pol.addPoint(temp_int1+51, temp_int2+89); pol.addPoint(temp_int1+103, temp_int2+59); pol.addPoint(temp_int1+103, temp_int2); pol.addPoint(temp_int1+51, temp_int2-30); pol.addPoint(temp_int1, temp_int2); aMolecule.getGraphics().drawPolygon(pol); int id2; for (int i=0; i<6; i++) { id2 = aMolecule.cursor_on_atom( pol.xpoints[i],pol.ypoints[i]); if (id2 != -1) aMolecule.redrawAtom(id2,Color.blue); } this.x = temp_int1; this.y = temp_int2; break; case CYCLO5: // redraw the polygon from a possible existing case ARO5: // atom aMolecule.paint(aMolecule.getGraphics()); Polygon pol5 = new Polygon(); pol5.addPoint(temp_int1, temp_int2); pol5.addPoint(temp_int1+16, temp_int2+51); pol5.addPoint(temp_int1+71, temp_int2+51); pol5.addPoint(temp_int1+88, temp_int2); pol5.addPoint(temp_int1+44, temp_int2-32); pol5.addPoint(temp_int1, temp_int2); aMolecule.getGraphics().drawPolygon(pol5); int id5; for (int i=0; i<5; i++) { id5 = aMolecule.cursor_on_atom( pol5.xpoints[i],pol5.ypoints[i]); if (id5 != -1) aMolecule.redrawAtom(id5,Color.blue); } this.x = temp_int1; this.y = temp_int2; break; default:break; }// end switch } else { this.x = -1; this.y = -1; } return true; } // Function called by handleEvent, that acts when the mouse button is released public boolean LocalmouseUp(Event e, int x, int y) { Rectangle r = drawing_area.bounds(); int temp_int1 = x - r.x; int temp_int2 = y - r.y; if (x>r.x && xr.y && y= r.width || polygon_arrayy[i] >= r.height) must_exit = true; if (must_exit) { this.x = -1; this.y = -1; break; } int indices[] = new int[6]; for (int i=0; i<6; i++) { indices[i] = aMolecule.cursor_on_atom( polygon_arrayx[i], polygon_arrayy[i]); if (indices[i] == -1) indices[i] = aMolecule.AddAtom( polygon_arrayx[i], polygon_arrayy[i], 6); } if (current_selected == ARO6) { aMolecule.AddBond(indices[0],indices[1],4); aMolecule.AddBond(indices[1],indices[2],4); aMolecule.AddBond(indices[2],indices[3],4); aMolecule.AddBond(indices[3],indices[4],4); aMolecule.AddBond(indices[4],indices[5],4); aMolecule.AddBond(indices[5],indices[0],4); } else { aMolecule.AddBond(indices[0],indices[1],1); aMolecule.AddBond(indices[1],indices[2],1); aMolecule.AddBond(indices[2],indices[3],1); aMolecule.AddBond(indices[3],indices[4],1); aMolecule.AddBond(indices[4],indices[5],1); aMolecule.AddBond(indices[5],indices[0],1); } aMolecule.paint(aMolecule.getGraphics()); this.x = -1; this.y = -1; break; case ARO5: // See comments for 6 membered ring, above. case CYCLO5: double scale_fac5 = 1.0+(double)(temp_int2 - this.y)/100.0; int polygon5_arrayx[] = new int[6]; int polygon5_arrayy[] = new int[6]; polygon5_arrayx[0] = 0; polygon5_arrayy[0] = 0; polygon5_arrayx[1] = (int)(scale_fac5*16.0); polygon5_arrayy[1] = (int)(scale_fac5*51.0); polygon5_arrayx[2] = (int)(scale_fac5*71.0); polygon5_arrayy[2] = (int)(scale_fac5*51.0); polygon5_arrayx[3] = (int)(scale_fac5*88.0); polygon5_arrayy[3] = 0; polygon5_arrayx[4] = (int)(scale_fac5*44.0); polygon5_arrayy[4] = (int)(scale_fac5*(-32.0)); polygon5_arrayx[5] = 0; polygon5_arrayy[5] = 0; double theta5 = Math.PI * ((double)(temp_int1-this.x)/100.0); double cost5 = Math.cos(theta5); double sint5 = Math.sin(theta5); int tempx5, tempy5; for (int i=0; i<6; i++) { tempx5 = polygon5_arrayx[i]; tempy5 = polygon5_arrayy[i]; polygon5_arrayx[i] = (int)((double)tempx5*cost5) - (int)((double)tempy5*sint5) + this.x; polygon5_arrayy[i] = (int)((double)tempx5*sint5) + (int)((double)tempy5*cost5) + this.y; } for (int i=0; i<6; i++) { tempx5 = aMolecule.cursor_on_atom( polygon5_arrayx[i], polygon5_arrayy[i]); if (tempx5 != -1) { polygon5_arrayx[i] = aMolecule.atoms_x[tempx5]; polygon5_arrayy[i] = aMolecule.atoms_y[tempx5]; aMolecule.redrawAtom(tempx5,Color.blue); } } boolean must_exit5 = false; for (int i=0; i<5; i++) if (polygon5_arrayx[i] <= 0 || polygon5_arrayy[i] <= 0 || polygon5_arrayx[i] >= r.width || polygon5_arrayy[i] >= r.height) must_exit5 = true; if (must_exit5) { this.x = -1; this.y = -1; break; } int indices5[] = new int[5]; for (int i=0; i<5; i++) { indices5[i] = aMolecule.cursor_on_atom( polygon5_arrayx[i], polygon5_arrayy[i]); if (indices5[i] == -1) indices5[i] = aMolecule.AddAtom( polygon5_arrayx[i], polygon5_arrayy[i], 6); } if (current_selected == ARO5) { aMolecule.AddBond(indices5[0],indices5[1],4); aMolecule.AddBond(indices5[1],indices5[2],4); aMolecule.AddBond(indices5[2],indices5[3],4); aMolecule.AddBond(indices5[3],indices5[4],4); aMolecule.AddBond(indices5[4],indices5[0],4); } else { aMolecule.AddBond(indices5[0],indices5[1],1); aMolecule.AddBond(indices5[1],indices5[2],1); aMolecule.AddBond(indices5[2],indices5[3],1); aMolecule.AddBond(indices5[3],indices5[4],1); aMolecule.AddBond(indices5[4],indices5[0],1); } aMolecule.paint(aMolecule.getGraphics()); this.x = -1; this.y = -1; break; default:break; }// end switch } // If mouse button released outside the drawing area, // cancel ring drawing else if ((current_selected == ARO6 || current_selected == CYCLO6 || current_selected == ARO5 || current_selected == CYCLO5) && this.x > -1 && this.y > -1) { aMolecule.paint(aMolecule.getGraphics()); this.x = -1; this.y = -1; } return true; }// End mouseUp // This function has been ripped off from David Flanagan's // Java in a Nutshell, O'reilly & associates, Inc. // It creates the constraints according to the parameters. public void constrain(Container container, Component component, int grid_x, int grid_y, int grid_width, int grid_height, int fill, int anchor, double weight_x, double weight_y, int top, int left, int bottom, int right) { GridBagConstraints c = new GridBagConstraints(); c.gridx = grid_x; c.gridy = grid_y; c.gridwidth = grid_width; c.gridheight = grid_height; c.fill = fill; c.anchor = anchor; c.weightx = weight_x; c.weighty = weight_y; if (top+bottom+left+right > 0) c.insets = new Insets(top,left,bottom,right); ((GridBagLayout)container.getLayout()).setConstraints(component,c); container.add(component); } }// End MoleculeEditor_1_0 class /* * This is the Molecule_1_0 class. It is used to store and handle all the aspects * of a molecule creation, modifications, drawing, etc... * Everything is stored in arrays. The maximum size is 100 atoms and * 250 bonds. It is never checked if these limits are passed! */ class Molecule_1_0 extends Canvas{ private protected static final int MAX_ATOMS = 100; private protected static final int MAX_BONDS = 250; protected int atoms_x[]; protected int atoms_y[]; protected int nbAtoms; protected int nbBonds; protected int bonds_1[]; protected int bonds_2[]; protected int bonds_type[]; protected int atoms_type[]; protected byte atoms_degree[]; protected boolean atoms_selected[]; protected boolean bonds_selected[]; private protected static final int MAX_RADIUS = 10; protected Polygon bonds_area[]; protected Font font; public Molecule_1_0() { atoms_x = new int [MAX_ATOMS]; atoms_y = new int [MAX_ATOMS]; atoms_type = new int [MAX_ATOMS]; atoms_degree = new byte [MAX_ATOMS]; bonds_1 = new int [MAX_BONDS]; bonds_2 = new int [MAX_BONDS]; bonds_type = new int [MAX_BONDS]; atoms_selected = new boolean [MAX_ATOMS]; bonds_selected = new boolean [MAX_BONDS]; bonds_area = new Polygon [MAX_BONDS]; nbAtoms = 0; nbBonds = 0; font = new Font("Courier",Font.PLAIN,10); } public int AddAtom(int a, int b, int at) { atoms_x[nbAtoms] = a; atoms_y[nbAtoms] = b; atoms_type[nbAtoms] = at; atoms_degree[nbAtoms] = 0; atoms_selected[nbAtoms++] = false; return nbAtoms-1; } public boolean AddBond(int id1, int id2, int bt) { if (id1 < nbAtoms && id2 < nbAtoms) { int id = BondExist(id1, id2); if (id != -1) { if (bonds_type[id] == bt) return false; else { bonds_type[id] = bt; return true; } } bonds_1[nbBonds] = id1; bonds_2[nbBonds] = id2; bonds_type[nbBonds] = bt; bonds_area[nbBonds] = find_polygon(id1,id2); bonds_selected[nbBonds++] = false; atoms_degree[id1] += 1; atoms_degree[id2] += 1; return true; } else { return false; } } private Polygon find_polygon(int x, int y) { Polygon pol = new Polygon(); int x1 = atoms_x[y] - atoms_x[x]; int y1 = atoms_y[y] - atoms_y[x]; int x2 = -1 * y1; int y2 = x1; double norm1 = Math.sqrt((double)(x2*x2+y2*y2)); pol.addPoint(atoms_x[x]+(int)(5.0*(double)x2/norm1)+(int)(8.0*(double)x1/norm1), atoms_y[x]+(int)(5.0*(double)y2/norm1)+(int)(8.0*(double)y1/norm1)); pol.addPoint(atoms_x[x]+(int)(-5.0*(double)x2/norm1)+(int)(8.0*(double)x1/norm1), atoms_y[x]+(int)(-5.0*(double)y2/norm1)+(int)(8.0*(double)y1/norm1)); pol.addPoint(atoms_x[y]+(int)(-5.0*(double)x2/norm1)+(int)(-8.0*(double)x1/norm1), atoms_y[y]+(int)(-5.0*(double)y2/norm1)+(int)(-8.0*(double)y1/norm1)); pol.addPoint(atoms_x[y]+(int)(5.0*(double)x2/norm1)+(int)(-8.0*(double)x1/norm1), atoms_y[y]+(int)(5.0*(double)y2/norm1)+(int)(-8.0*(double)y1/norm1)); return pol; } public boolean RemoveBond(int id1, int id2) { if (id1 < nbAtoms && id2 < nbAtoms) { for (int i=0; i=0; i--) if (atoms_selected[i]) RemoveAtom(i); for (int i=nbBonds-1; i>=0; i--) if (bonds_selected[i]) RemoveBond(i); paint(this.getGraphics()); } int BondExist(int id1, int id2) { if (id1 != id2 && id1 < nbAtoms && id2 < nbAtoms) { for (int i=0; i 122 || (int)at.charAt(1) < 65) return char2type(at.charAt(0)); else if (at.length() == 2 || (int)at.charAt(2) > 122 || (int)at.charAt(2) < 65) return char2type(at.charAt(0), at.charAt(1)); else return 200; } public int cursor_on_atom(int x, int y) { for (int i=0; i -1) for (int i=0; i= nbBonds) return; Graphics g = this.getGraphics(); g.setColor(c); switch (bonds_type[id]) { case 3: x1 = atoms_x[bonds_2[id]] - atoms_x[bonds_1[id]]; y1 = atoms_y[bonds_2[id]] - atoms_y[bonds_1[id]]; x2 = -1 * y1; y2 = x1; norm1 = Math.sqrt((double)(x2*x2+y2*y2)); g.drawLine( atoms_x[bonds_1[id]]+(int)(5.0*(double)x2/norm1), atoms_y[bonds_1[id]]+(int)(5.0*(double)y2/norm1), atoms_x[bonds_2[id]]+(int)(5.0*(double)x2/norm1), atoms_y[bonds_2[id]]+(int)(5.0*(double)y2/norm1)); g.drawLine( atoms_x[bonds_1[id]]+(int)(-5.0*(double)x2/norm1), atoms_y[bonds_1[id]]+(int)(-5.0*(double)y2/norm1), atoms_x[bonds_2[id]]+(int)(-5.0*(double)x2/norm1), atoms_y[bonds_2[id]]+(int)(-5.0*(double)y2/norm1)); g.drawLine(atoms_x[bonds_1[id]], atoms_y[bonds_1[id]], atoms_x[bonds_2[id]], atoms_y[bonds_2[id]]); break; case 2: x1 = atoms_x[bonds_2[id]] - atoms_x[bonds_1[id]]; y1 = atoms_y[bonds_2[id]] - atoms_y[bonds_1[id]]; x2 = -1 * y1; y2 = x1; norm1 = Math.sqrt((double)(x2*x2+y2*y2)); g.drawLine( atoms_x[bonds_1[id]]+(int)(4.0*(double)x2/norm1), atoms_y[bonds_1[id]]+(int)(4.0*(double)y2/norm1), atoms_x[bonds_2[id]]+(int)(4.0*(double)x2/norm1), atoms_y[bonds_2[id]]+(int)(4.0*(double)y2/norm1)); g.drawLine( atoms_x[bonds_1[id]]+(int)(-4.0*(double)x2/norm1), atoms_y[bonds_1[id]]+(int)(-4.0*(double)y2/norm1), atoms_x[bonds_2[id]]+(int)(-4.0*(double)x2/norm1), atoms_y[bonds_2[id]]+(int)(-4.0*(double)y2/norm1)); break; case 4: x1 = atoms_x[bonds_2[id]] - atoms_x[bonds_1[id]]; y1 = atoms_y[bonds_2[id]] - atoms_y[bonds_1[id]]; norm1 = Math.sqrt((double)(x1*x1+y1*y1)); g.drawLine(atoms_x[bonds_1[id]], atoms_y[bonds_1[id]], atoms_x[bonds_1[id]] + (int)((double)x1/5.0), atoms_y[bonds_1[id]] + (int)((double)y1/5.0)); g.drawLine( atoms_x[bonds_1[id]] + (int)(2.0*(double)x1/5.0), atoms_y[bonds_1[id]] + (int)(2.0*(double)y1/5.0), atoms_x[bonds_1[id]] + (int)(3.0*(double)x1/5.0), atoms_y[bonds_1[id]] + (int)(3.0*(double)y1/5.0)); g.drawLine( atoms_x[bonds_1[id]] + (int)(4.0*(double)x1/5.0), atoms_y[bonds_1[id]] + (int)(4.0*(double)y1/5.0), atoms_x[bonds_2[id]], atoms_y[bonds_2[id]]); break; case 1: default: g.drawLine(atoms_x[bonds_1[id]], atoms_y[bonds_1[id]], atoms_x[bonds_2[id]], atoms_y[bonds_2[id]]); break; } } public void redrawBond(int id, Color c) { if (id < 0 || id >= nbBonds) return; simpleRedrawBond(id, c); if (atoms_selected[bonds_1[id]]) redrawAtom(bonds_1[id],Color.red); else redrawAtom(bonds_1[id],Color.black); if (atoms_selected[bonds_2[id]]) redrawAtom(bonds_2[id],Color.red); else redrawAtom(bonds_2[id],Color.black); }// end redraw_atom public void redrawBond(int id) { if (id > -1 && id < nbBonds) { redrawAtom(bonds_1[id]); redrawAtom(bonds_2[id]); } } public void redrawAtom(int id, Color c) { Graphics g = this.getGraphics(); g.setColor(Color.lightGray); g.fillRect(atoms_x[id]-3,atoms_y[id]-7,10,10); g.setColor(c); g.drawString(at2string(atoms_type[id]), atoms_x[id]-2, atoms_y[id]+2); }// end redraw_atom public void redrawAtom(int id) { Graphics g = this.getGraphics(); g.setColor(Color.lightGray); if (atoms_type[id] == 6) g.fillRect(atoms_x[id]-3,atoms_y[id]-7,10,10); g.setColor(Color.black); if (atoms_degree[id] == 0) { if (atoms_selected[id]) redrawAtom(id,Color.red); else redrawAtom(id,Color.black); } else { for (int i=0; i maxx) maxx = xpoints[i]; if (xpoints[i] < minx) minx = xpoints[i]; if (ypoints[i] > maxy) maxy = ypoints[i]; if (ypoints[i] < miny) miny = ypoints[i]; } width = maxx; height = maxy; if (width < 20) width = 20; if (height < 20) height = 20; } } public ImageLinesButton_1_0 (String name) { npoints=0; width = 20; height = 20; this.name = new String(name); } public boolean handleEvent(Event e) { Graphics g = this.getGraphics(); switch (e.id) { case Event.MOUSE_DOWN: reverse_paint(g); return false; case Event.MOUSE_UP: this.paint(g); MoleculeEditor_1_0.buttonMouseUp(new String(this.name)); return false; default: break; } return true; } public Dimension preferredSize() { return new Dimension(width+2*MARGIN,height+2*MARGIN); } public Dimension minimumSize() { return new Dimension(width+2*MARGIN,height+2*MARGIN); } public void reverse_paint(Graphics g) { g.setColor(Color.black); g.fillRoundRect(0,0,width+2*MARGIN,height+2*MARGIN,10,10); g.setColor(Color.white); g.drawRoundRect(0,0,width+2*MARGIN-1,height+2*MARGIN-1,10,10); for (int i=0; i