///////////////////////////////////////////////////////////////////
import java.awt.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;
import java.applet.Applet;
//////////////////////////////////////////////////////////////////
public class QuickPDB extends Applet {
// QUICKPDB (JAVA) by Ilya Shindyalov and Phil Bourne
// Copyright (c) 1996-1998 Regents of the University of California.
//
// Users and possessors of this source code are hereby granted a
// nonexclusive, royalty-free copyright and design patent license to
// use this code in individual software. License is not granted for
// commercial resale, in whole or in part, without prior written
// permission from the Regents of the University of California.
// This source is provided "AS IS" without expressed or implied 
// warranty of any kind.
//       
// For further information contact:
// E-Mail:         consult@sdsc.edu
// 
// Surface Mail:   Information Center
//                 SDSC
//                 UCSD 0505
//                 9500 Gilman Drive
//                 La Jolla, CA 92093-0505
//
  String copyright[]={
"**     QUICKPDB (JAVA) by Ilya Shindyalov and Phil Bourne",
"**     Copyright (c) 1996-1998 Regents of the University of California.",
"**",
"**     Users and possessors of this source code are hereby granted a",
"**     nonexclusive, royalty-free copyright and design patent license to",
"**     use this code in individual software. License is not granted for",
"**     commercial resale, in whole or in part, without prior written",
"**     permission from the Regents of the University of California.",
"**     This source is provided \"AS IS\" without expressed or implied",
"**     warranty of any kind.",
"**",          
"**     For further information contact:",
"**     E-Mail:         consult@sdsc.edu",
"**",
"**     Surface Mail:   Information Center",
"**                     SDSC",
"**                     UCSD 0505",
"**                     9500 Gilman Drive",
"**                     La Jolla, CA 92093-0505",
"**", 
"**     Last update Sep. 8, 1998"};


  QpdbButton qpdbButton;

//////////////////////////////////////////////////////////////////
public void init()
{
}
//////////////////////////////////////////////////////////////////
public void start()
{
  /*
  pdb_file = "3ebx"; 
  html_url = "http://cl.sdsc.edu";
  cgi_url = "http://cl.sdsc.edu/cgi-bin";
  moose_db = "/misc/rcsb/pdbplus";
  */
    qpdbButton=new QpdbButton(this);
    add(qpdbButton);
    qpdbButton.show();
    setBackground(Color.white);
    
}
//////////////////////////////////////////////////////////////////
  public void stop() {
    qpdbButton.disposeQpdbFrame();
  }
//////////////////////////////////////////////////////////////////

}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class QpdbButton extends Button {

  QuickPDB qpdb;
  QpdbFrame qpdbFrame;

////////////////////////////////////////////////////////////////////////////
  QpdbButton(QuickPDB qpdb_) {
    super("QuickPDB");
    qpdb=qpdb_;
    qpdbFrame = null;
  }
////////////////////////////////////////////////////////////////////////////
  public boolean action(Event e, Object w) {

    qpdbFrame=new QpdbFrame("QuickPDB", qpdb);
    qpdbFrame.setTitle("QuickPDB");
    //qpdbFrame.setForeground(new Color(255, 255, 255));
    //qpdbFrame.setBackground(new Color(0, 0, 0));
    qpdbFrame.applet=qpdb;
    qpdbFrame.resize(700, 600);
    qpdbFrame.show();

    if(qpdbFrame.pdb_file!=null && qpdbFrame.first_load)
      {
	qpdbFrame.first_load=false;
	qpdbFrame.loadCompound();
      }
    return true;
  }
////////////////////////////////////////////////////////////////////////////
  public void disposeQpdbFrame() {
    if(qpdbFrame != null) qpdbFrame.dispose();
  }

}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class QpdbFrame extends  Frame
{
  Applet applet;
  String html_url, cgi_url, pdb_file, rcsb_explore_url, moose_db;
  String header, source;

  int propertiesTay[][];
  String propertiesTayName[];

  Color currentColor, initColor, seColors[][];
  String seqLine[];
  String ksLine[];
  int nEnt, nSE[], bfac[][], exp[][], maxNSE;
  double bfac_min, bfac_max, exp_min, exp_max;
  String entName[];
  int seqPosEnt[], seqPosSE[], nSeqPos, nSeqChar, seqCharLM;
 
  int mouseStatus;
  double xyz[][][];
  double cc[][];
  double scale, scale_init;
  double shiftx, shifty, shiftz, shiftx_init, shifty_init;
  double x_o, y_o, z_o;

  Panel panel1, panel2;
  Image sdsc_logo;
  boolean stereo, first_load;

// view panel 
  Button b_help, b_reset, b_details, b_getCom, b_close;
  Checkbox c_stereo;
  List ent_list;
  SeqPanel seq; 
  StrucCanvas struc;
  Canvas seq_pos;
  LogoCanvas logo, logo1;

  Choice colorChoice, mouseChoice, mouseChoiceSeq, propChoice,
    propTayChoice;
  Component tmp;
  TextField getCom;


  GridBagLayout gridbag=new GridBagLayout();
  GridBagConstraints c=new GridBagConstraints();
//////////////////////////////////////////////////////////////////
public QpdbFrame(String text, QuickPDB applet_) 
  {
    super(text);
    applet = applet_;
    pdb_file = applet.getParameter("struc_id");
    html_url = applet.getParameter("html_url");
    cgi_url = applet.getParameter("cgi_url");
    rcsb_explore_url = applet.getParameter("rcsb_explore_url");
    moose_db = applet.getParameter("moose_db");
    
    first_load=true;
    setFont(new Font("Courier", Font.PLAIN, 10));
    setBackground(Color.white);


    nSeqPos = 0;
    seqCharLM = 100;

    mouseStatus=0;
    nEnt=0;
    cc=new double[3][3];
    for(int i=0; i<3; i++)
      for(int j=0; j<3; j++) {cc[i][j]=0.0; if(i==j)cc[i][j]=1.0; }

    sdsc_logo=null;
    stereo=false;

    ent_list=new List(4, false);
    b_details = new Button("More Info");
    b_help=new Button("Help");
    b_reset=new Button("Reset");
    b_close=new Button("Close");
    c_stereo=new Checkbox("Stereo");

    propChoice = new Choice();
    propChoice.addItem("Secondary Structure");
    propChoice.addItem("B Factor");
    propChoice.addItem("Exposure");

    int propertiesTay_[][]={
      /* A */  {1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0},
	       /* V */  {1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0},
	       /* L */  {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
	       /* I */  {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
	       /* C */  {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
	       /* M */  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	       /* P */  {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0},
	       /* F */  {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
	       /* Y */  {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0},
	       /* W */  {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0},
	       /* D */  {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
	       /* N */  {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
	       /* E */  {0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0},
	       /* Q */  {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	       /* H */  {1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0},
	       /* S */  {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0},
	       /* T */  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 
	       /* R */  {0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0},
	       /* K */  {1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0},
	       /* G */  {1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1}};
    //       1  2  3  4  5  6  7  8  9 10 11 
    
    String propertiesTayName_[]={
      "Hydrophobic", "Polar", "Small", "Proline", "Tiny", "Aliphatic", 
      "Aromatic", "Positive", "Negative", "Charged", "Glycine"};
    //  1-hydrophobic, 2-polar, 3-small, 4-pro, 5-tiny, 6-aliphactic,
    //  7-aromatic, 8-positive, 9-negative, 10-charged, 11-gly. 
    
    propertiesTay=propertiesTay_;
    propertiesTayName=propertiesTayName_;

    propTayChoice = new Choice();

    for(int ip = 0; ip < propertiesTayName.length; ip++)
      propTayChoice.addItem(propertiesTayName[ip]);
       
    initColor = Color.red;
    colorChoice=new Choice();
    colorChoice.addItem("Blue");
    colorChoice.addItem("Cyan");
    colorChoice.addItem("Green");
    colorChoice.addItem("Magenta");
    colorChoice.addItem("Orange");
    colorChoice.addItem("Pink");
    colorChoice.addItem("Red");
    colorChoice.addItem("Yellow");
    colorChoice.select("Cyan");
    currentColor=Color.cyan;

    mouseChoice=new Choice();
    mouseChoice.addItem("Rotate");
    mouseChoice.addItem("Translate");
    mouseChoice.addItem("Zoom");
    mouseChoice.select("Rotate");
    mouseStatus=0;

    seq_pos=new Canvas();
    seq_pos.setForeground(new Color(255, 255, 255));
    seq_pos.setBackground(new Color(0, 0, 0));
    seq_pos.resize(80, 30);

    seq=new SeqPanel(this);    
    seq.setForeground(new Color(255, 255, 255));
    seq.setBackground(new Color(0, 0, 0));

    seq.resize(500, 200);
    struc=new StrucCanvas(this);       
    struc.setForeground(new Color(255, 255, 255));
    struc.setBackground(new Color(0, 0, 0));
    struc.resize(500, 400);
    logo=new LogoCanvas(this);
    logo.resize(400, 13);

    panel1=new Panel();
    panel2 = new Panel();
    //panel1.setBackground(new Color(255, 255, 255));
    //panel1.setForeground(new Color(0, 0, 0));
    panel1.setLayout(gridbag);
    panel2.setLayout(gridbag);

    addComponent(panel2, seq_pos, 0, 0, 2, 3, 
		 GridBagConstraints.CENTER, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);

    Label label = new Label("Sequence: drag or click to select residues | 3D: double click to select residue");
    label.setForeground(Color.red);
    addComponent(panel1, label, 0, 0, 3, 1, 
		 GridBagConstraints.WEST, 
		 GridBagConstraints.NONE, 1.0, 0.0);
    
    
    label = new Label("Polymers:");
    label.setForeground(Color.red);
    addComponent(panel2, label, 0, 3, 2, 1, 
		 GridBagConstraints.CENTER, 
		 GridBagConstraints.NONE, 1.0, 0.0);
    

    if(pdb_file != null) {
      addComponent(panel2, ent_list, 0, 4, 2, 2, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.VERTICAL, 1.0, 1.0, 5, 0, 5, 0);
    }
    else {
      addComponent(panel2, ent_list, 0, 4, 2, 1, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.VERTICAL, 1.0, 1.0, 5, 0, 5, 0);
      b_getCom = new Button("Load");
      getCom = new TextField(4);

      addComponent(panel2, b_getCom, 0, 5, 1, 1, 
		   GridBagConstraints.WEST, 
		   GridBagConstraints.HORIZONTAL, 1.0, 0.0);

      addComponent(panel2, getCom, 1, 5, 1, 1, 
		   GridBagConstraints.WEST, 
		   GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    }


    addComponent(panel2, propChoice, 0, 6, 2, 1, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);

    addComponent(panel2, propTayChoice, 0, 7, 2, 1, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);

    addComponent(panel2, c_stereo, 0, 8, 2, 1, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);


    addComponent(panel2, new Label("Mouse:"), 0, 9, 1, 1, 
		 GridBagConstraints.WEST, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    
    addComponent(panel2, mouseChoice, 1, 9, 1, 1, 
		 GridBagConstraints.WEST, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    
    addComponent(panel2, new Label("Color:"), 0, 10, 1, 1, 
		 GridBagConstraints.WEST, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    
    addComponent(panel2, colorChoice, 1, 10, 1, 1, 
		 GridBagConstraints.WEST, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0);

      addComponent(panel2, ent_list, 0, 4, 2, 2, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.VERTICAL, 1.0, 1.0, 5, 0, 5, 0);

    if(pdb_file != null) {
      addComponent(panel2, b_help, 0, 11, 2, 1, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    }
    else {
      addComponent(panel2, b_details, 0, 11, 1, 1, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.HORIZONTAL, 1.0, 0.0, 1, 1, 1, 1);
      addComponent(panel2, b_help, 1, 11, 1, 1, 
		   GridBagConstraints.NORTH, 
		   GridBagConstraints.HORIZONTAL, 1.0, 0.0);
    }

     addComponent(panel2, b_reset, 0, 12, 1, 1, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0, 1, 1, 1, 1);

     addComponent(panel2, b_close, 1, 12, 1, 1, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.HORIZONTAL, 1.0, 0.0, 1, 1, 1, 1);

    addComponent(panel1, panel2, 0, 2, 2, 10,
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.BOTH, 1.0, 0.1, 1, 1, 1, 1);

    addComponent(panel1, seq, 0, 1, 3, 1,
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.BOTH, 10.0, 1.0);

    addComponent(panel1, struc, 2, 2, 1, 10, 
		 GridBagConstraints.NORTH, 
		 GridBagConstraints.BOTH, 10.0, 4.0);

    addComponent(panel1, logo, 0, 12, 3, 1,
		 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, 
		 1.0, 0.0);

    this.setLayout(gridbag);

    addComponent(this, panel1, 0, 0, 1, 1, 
		 GridBagConstraints.NORTHWEST, 
		 GridBagConstraints.BOTH, 1.0, 1.0, 5, 5, 5, 5);

  }
//////////////////////////////////////////////////////////////////
public void addComponent(Container container, Component component,
			 int gridx, int gridy, int gridwidth, int gridheight,
			 int anchor, int fill, double weightx, double weighty)
{
    c.gridx=gridx; c.gridy=gridy; c.gridwidth=gridwidth;
    c.gridheight=gridheight; c.anchor=anchor; c.fill=fill; 
    c.weightx=weightx; c.weighty=weighty;
    ((GridBagLayout) container.getLayout()).setConstraints(component, c);
    container.add(component);
  }
//////////////////////////////////////////////////////////////////
public void addComponent(Container container, Component component,
			 int gridx, int gridy, int gridwidth, int gridheight,
			 int anchor, int fill, double weightx, double weighty,
			 int top, int left, int bottom, int right)
  {
    c.gridx=gridx; c.gridy=gridy; c.gridwidth=gridwidth;
    c.gridheight=gridheight; c.anchor=anchor; c.fill=fill; 
    c.weightx=weightx; c.weighty=weighty;
    c.insets=new Insets(top, left, bottom, right);
    ((GridBagLayout) container.getLayout()).setConstraints(component, c);
    container.add(component);
  }
//////////////////////////////////////////////////////////////////
public boolean handleEvent(Event event) 
  {
    switch(event.id) 
      {
      case WindowEvent.WINDOW_CLOSING:
	dispose();
	return true;

      case Event.ACTION_EVENT:
	if (event.target == b_reset) 
	  {
	    for(int i=0; i<3; i++)
	      for(int j=0; j<3; j++) {cc[i][j]=0.0; if(i==j)cc[i][j]=1.0; }
	    int iEnt, iSE;
	    for(iEnt=0; iEnt<nEnt; iEnt++)
	      for(iSE=0; iSE<nSE[iEnt]; iSE++)
		seColors[iEnt][iSE] = Color.red;
	    scale=scale_init;
	    shiftx=shiftx_init;
	    shifty=shifty_init;
	    seq.repaint();
	    struc.paint(struc.getGraphics());
	    return true;
	  }
	else if (event.target == b_details) {
	  try {
	    URL url=new URL(rcsb_explore_url + (rcsb_explore_url.endsWith("=") ? "" : "=") + pdb_file);
	    applet.getAppletContext().showDocument(url, pdb_file);
	    return true;
	  }
	  catch (MalformedURLException ex) {
	  }
	}
	else if (event.target == c_stereo) 
	  {
	    stereo=c_stereo.getState();
	    struc.repaint();
	    return true;
	  }
	else if (event.target == colorChoice) 
	  {
	    if(((String)event.arg).compareTo("Blue")==0) 
	      currentColor=Color.blue;
	    if(((String)event.arg).compareTo("Cyan")==0) 
	      currentColor=Color.cyan;
	    if(((String)event.arg).compareTo("Green")==0) 
	      currentColor=Color.green;
	    if(((String)event.arg).compareTo("Magenta")==0) 
	      currentColor=Color.magenta;
	    if(((String)event.arg).compareTo("Orange")==0) 
	      currentColor=Color.orange;
	    if(((String)event.arg).compareTo("Pink")==0) 
	      currentColor=Color.pink;
	    if(((String)event.arg).compareTo("Red")==0) 
	      currentColor=Color.red;
	    if(((String)event.arg).compareTo("Yellow")==0) 
	      currentColor=Color.yellow;
	    return true;
	  }
	else if (event.target == mouseChoice) 
	  {
	    if(((String)event.arg).compareTo("Rotate")==0) mouseStatus=0;
	    if(((String)event.arg).compareTo("Translate")==0) mouseStatus=1;
	    if(((String)event.arg).compareTo("Zoom")==0) mouseStatus=2;
	    return true;
	  }

	else if (event.target == propTayChoice) { // Taylor Prop 

	  int iProp = propTayChoice.getSelectedIndex();
	  int aa_encode[]={1, 0, 5, 11, 13, 8, 20, 15, 4, 0, 19, 3, 
			   6, 12, 0, 7, 14, 18, 16, 17, 0, 2, 10, 0, 9};
	  String aa_code = "AVLICMPFYWDNEQHSTRKG";
	  
	  Graphics g=seq_pos.getGraphics();
	  Dimension dim=seq_pos.size();
	  g.clearRect(0, 0, dim.width, dim.height);
	  for(int aa = 0 ; aa < 20; aa++) {
	    if(propertiesTay[aa][iProp] == 1) g.setColor(Color.red);
	    else g.setColor(Color.blue);
	    g.drawString(aa_code.substring(aa, aa+1), 
			 (aa%10)*10+5, 13+13*(aa/10));
	  }
	  
	  for(int jEnt=0; jEnt<nEnt; jEnt++)
	    for(int i=0; i<nSE[jEnt]; i++) {
	      seColors[jEnt][i] = Color.white;
	      int aa_char = (int)seqLine[jEnt].charAt(i);
	      if(aa_char < 65 || aa_char > 91) continue;
	      seColors[jEnt][i] = Color.blue;
	      int aa=aa_encode[(int)seqLine[jEnt].charAt(i)-65]-1;
	      if(aa<=19 && propertiesTay[aa][iProp] == 1) 
		seColors[jEnt][i] = Color.red;
	    }
	  seq.repaint();
	  struc.paint(struc.getGraphics());
	  return true;
	  
	  
	}

	else if (event.target == propChoice) { // Env Prop
	  if(propChoice.getSelectedIndex() == 0) { // Sec. Str.
	    Graphics g=seq_pos.getGraphics();
	    Dimension dim=seq_pos.size();
	    g.clearRect(0, 0, dim.width, dim.height);
	    g.setColor(Color.red);
	    g.drawString("Alpha (HGI)", 5, 13);
	    g.setColor(Color.blue);
	    g.drawString("Beta (E)", 75, 13);
	    g.setColor(Color.yellow);
	    g.drawString("Other", 5, 26);
	    for(int jEnt=0; jEnt<nEnt; jEnt++)
	      for(int i=0; i<nSE[jEnt]; i++)
		{
		  char ch=ksLine[jEnt].charAt(i);
		  seColors[jEnt][i]=Color.yellow;
		  if(ch=='H' || ch=='G' || ch=='I')
		    seColors[jEnt][i]=Color.red;
		  if(ch=='E') seColors[jEnt][i]=Color.blue;
		}
	    seq.repaint();
	    struc.paint(struc.getGraphics());
	    return true;
	  }
	  
	  if(propChoice.getSelectedIndex() == 1) { // B factor
	    Graphics g=seq_pos.getGraphics();
	    Dimension dim=seq_pos.size();
	    g.clearRect(0, 0, dim.width, dim.height);
	    for(int i=0; i<256; i+=4)
	      {
		g.setColor(new Color(i, 0, 255-i));
		g.drawLine(i/4+40, 3, i/4+40, 14);
	      }
	    g.setColor(Color.blue);
	    g.drawString(""+bfac_min, 5, 13);
	    g.setColor(Color.red);
	    g.drawString(""+bfac_max, 110, 13);
	    for(int jEnt=0; jEnt<nEnt; jEnt++)
	      for(int i=0; i<nSE[jEnt]; i++)
		{
		  seColors[jEnt][i] = bfac[jEnt][i] >= 0 ? 
		    new Color(bfac[jEnt][i], 0, 255-bfac[jEnt][i]) :
		    Color.white;
		}
	    seq.repaint();
	    struc.paint(struc.getGraphics());
	    return true;

	  }
	  if(propChoice.getSelectedIndex() == 2) { // Exposure
	    Graphics g=seq_pos.getGraphics();
	    Dimension dim=seq_pos.size();
	    g.clearRect(0, 0, dim.width, dim.height);
	    
	    for(int i=0; i<256; i+=4)
	      {
		g.setColor(new Color(i, 0, 255-i));
		g.drawLine(i/4+40, 3, i/4+40, 14);
	      }
	    
	    g.setColor(Color.blue);
	    g.drawString(""+exp_min, 5, 13);
	    g.setColor(Color.red);
	    g.drawString(""+exp_max, 110, 13);
	    for(int jEnt=0; jEnt<nEnt; jEnt++)
	      for(int i=0; i<nSE[jEnt]; i++)
		{
		  seColors[jEnt][i] = exp[jEnt][i] >= 0 ?
		    new Color(exp[jEnt][i], 0, 255-bfac[jEnt][i]) :
		    Color.white;
		}
	    seq.repaint();
	    struc.paint(struc.getGraphics());
	    return true;

	  }
	}
	else if (event.target == b_help) 
	  {
	    try {
	      URL url=new URL(html_url+"/quickpdb_help.html");
	      applet.getAppletContext().showDocument(url, "QuickPDB Help");
	      return true;
	    }
	    catch (MalformedURLException e) {
	    }
	  }
	else if (event.target == b_getCom) {
	  first_load = false;
	  pdb_file = getCom.getText();
	  loadCompound();
	}
	else if (event.target == b_close) {
	  dispose();
	}

      case Event.LIST_SELECT:
	if (event.target == ent_list) 
	  {
	    int jEnt=((Integer)event.arg).intValue();
	    
	    ent_list.deselect(jEnt);
	    for(int i=0; i<nSE[jEnt]; i++)
	      seColors[jEnt][i] = seColors[jEnt][i] == currentColor ?
		initColor : currentColor;
	    
	    seq.repaint();
	    struc.paint(struc.getGraphics());
	    return true;
	  }

      default:
	return false;
      }
  }
//////////////////////////////////////////////////////////////////
public void loadCompound() 
  {
    try
      {
	for(int i=0; i<3; i++)
	  for(int j=0; j<3; j++) {cc[i][j]=0.0; if(i==j)cc[i][j]=1.0; }
	
	Graphics g=seq_pos.getGraphics();
	Dimension dim=seq_pos.size();
	g.clearRect(0, 0, dim.width, dim.height);
	g.setColor(Color.red);
	g.drawString("Loading...Wait...", 5, 15);
	
	URL url=new URL(cgi_url+"/quickpdb.cgi?cmd=finfo&struc_id="+pdb_file+"&moose_db="+moose_db);
	//System.out.println("url="+url);
	URLConnection connection=url.openConnection();
	DataInputStream in=new DataInputStream(connection.getInputStream());
	if(ent_list.countItems()!=0) ent_list.clear();
	header = in.readLine();
	if(header.startsWith("id not found")) {
	  nEnt = 0;
	  seq.repaint();
	  struc.paint(struc.getGraphics());
	  g.clearRect(0, 0, dim.width, dim.height);
	  g.drawString(header, 5, 15);
	  return;
	}
	source = in.readLine();
	String line = source;
	/*
	if(line!=null) 
	  {
	    int i, n=(new Integer(in.readLine())).intValue();
	    big_text.setText(in.readLine());
	    for(i=1; i<n; i++) 
	      {
		big_text.appendText("\n");
		big_text.appendText(in.readLine());
	      }
	  }
	*/	

	seq.seqPosY=0;
	
	nEnt=(new Integer(in.readLine())).intValue();
	nSE=new int [nEnt];
	seqLine=new String [nEnt];
	ksLine=new String [nEnt];
	xyz=new double [nEnt][][];
	seColors=new Color [nEnt][];
	bfac=new int [nEnt][];
	exp = new int [nEnt][];
	entName=new String [nEnt];
	for(int i=0; i<nEnt; i++) 
	  {
	    entName[i]=in.readLine();
//	    System.out.print(entName[i]);
//	    System.out.print("\n");
	    ent_list.addItem(entName[i]);
	  }
	Double d=new Double(0.0);
	maxNSE=0;
	int iEnt, i, iSE;
	for(iEnt=0; iEnt<nEnt; iEnt++)
	  {
	    nSE[iEnt]=(new Integer(in.readLine())).intValue();
	    if(nSE[iEnt]>maxNSE) maxNSE=nSE[iEnt];
	    seqLine[iEnt]=in.readLine();
	    ksLine[iEnt]=in.readLine();
	    xyz[iEnt]=new double[nSE[iEnt]][3];
	    seColors[iEnt]=new Color [nSE[iEnt]];
	    bfac[iEnt]=new int [nSE[iEnt]];
	    exp[iEnt] = new int [nSE[iEnt]];

	    bfac_min = d.valueOf(in.readLine()).doubleValue();
	    bfac_max = d.valueOf(in.readLine()).doubleValue();

	    int ind1=1, ind2;
	    line=in.readLine();
	    Integer intg=new Integer(0);
	    for(iSE=0; iSE<nSE[iEnt]; iSE++)
	      {
		ind2=line.indexOf(' ', ind1);
		bfac[iEnt][iSE]=
		  (intg.valueOf(line.substring(ind1, ind2))).intValue();
		ind1=ind2+1;
	      }

	    exp_min = d.valueOf(in.readLine()).doubleValue();
	    exp_max = d.valueOf(in.readLine()).doubleValue();
	    line=in.readLine();
	    ind1=1;
	    for(iSE=0; iSE<nSE[iEnt]; iSE++)
	      {
		ind2=line.indexOf(' ', ind1);
		exp[iEnt][iSE]=
		  (intg.valueOf(line.substring(ind1, ind2))).intValue();
		ind1=ind2+1;
	      }

	    for(iSE=0; iSE<nSE[iEnt]; iSE++)
	      {
		seColors[iEnt][iSE]=Color.red;
		line=in.readLine();
		xyz[iEnt][iSE][0]=(d.valueOf(line.substring(0,9))).doubleValue();
		xyz[iEnt][iSE][1]=(d.valueOf(line.substring(10,19))).doubleValue();
		xyz[iEnt][iSE][2]=(d.valueOf(line.substring(20,29))).doubleValue();
	      }
	  }

	scale();
	
	seq.repaint();
	struc.paint(struc.getGraphics());
	g.clearRect(0, 0, dim.width, dim.height);

      }
    
    catch (MalformedURLException e)
      {
	ent_list.addItem("MalformedURLException");
      }
    catch (IOException e)
      {
	ent_list.addItem("IOException");
      }
    
  }

//////////////////////////////////////////////////////////////////
  public void scale() {
    int i, j, iEnt;

	double xmin=10000.0, xmax=-10000.0, 
	  ymin=10000.0, ymax=-10000.0, 
	  zmin=10000.0, zmax=-10000.0;
	for(iEnt=0; iEnt<nEnt; iEnt++)
	  for(i=0; i<nSE[iEnt]; i++)
	    {
	      if(xyz[iEnt][i][0]>80000.0) continue;
	      if(xyz[iEnt][i][0]<xmin) xmin=xyz[iEnt][i][0];
	      if(xyz[iEnt][i][1]<ymin) ymin=xyz[iEnt][i][1];
	      if(xyz[iEnt][i][2]<zmin) zmin=xyz[iEnt][i][2];
	      if(xyz[iEnt][i][0]>xmax) xmax=xyz[iEnt][i][0];
	      if(xyz[iEnt][i][1]>ymax) ymax=xyz[iEnt][i][1];
	      if(xyz[iEnt][i][2]>zmax) zmax=xyz[iEnt][i][2];
	    }
	Dimension dstruc=struc.size();
	double delta=xmax-xmin;
	if(ymax-ymin>delta) delta=ymax-ymin;
	if(zmax-zmin>delta) delta=zmax-zmin;
	scale=Math.min(dstruc.width, dstruc.height)/delta;
	scale_init=scale;
	shiftx=dstruc.width/2.0/scale;
	shifty=dstruc.height/2.0/scale;
	shiftx_init=shiftx;
	shifty_init=shifty;
	shiftz=zmax;
	x_o=(xmax+xmin)/2.0;
	y_o=(ymax+ymin)/2.0;
	z_o=(zmax+zmin)/2.0;
	
	for(iEnt=0; iEnt<nEnt; iEnt++)
	  for(i=0; i<nSE[iEnt]; i++)
	    {
	      if(xyz[iEnt][i][0]>80000.0) continue;
	      xyz[iEnt][i][0]-=x_o;
	      xyz[iEnt][i][1]-=y_o;
	      xyz[iEnt][i][2]-=z_o;
	    }

	Dimension dseq = seq.seqCanvas.size();
	nSeqChar = ((dseq.width - seqCharLM) / seq.seqCharX) / 10 * 10;

	nSeqPos = 0;
	for(i = 0; i < nEnt; i++) 
	  nSeqPos += (nSE[i] + 1) / nSeqChar + 1;
	seqPosEnt = new int [nSeqPos];
	seqPosSE = new int [nSeqPos];
	nSeqPos = 0;
	for(i = 0; i < nEnt; i++) {
	  for(j = 0; j < nSE[i]; j += nSeqChar) {
	    seqPosEnt[nSeqPos] = i;
	    seqPosSE[nSeqPos] = j;
	    nSeqPos++;
	  }
	}

  }

}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
  /*
class TitleLabel extends Label {
  QuickPDBPanel qpdb;

//////////////////////////////////////////////////////////////////
  TitleLabel(QuickPDBPanel qpdb_, String text)
  {
    super(text);
    qpdb=qpdb_;
  }
//////////////////////////////////////////////////////////////////
  public void processMouseEvent(MouseEvent e) {

    System.out.println("mouse event");

}
//////////////////////////////////////////////////////////////////
public boolean gotFocus(Event e, Object o)
  {
    System.out.println("got focus");
    setForeground(Color.yellow);
    return true;
  }
//////////////////////////////////////////////////////////////////
 public boolean lostFocus(Event e, Object o)
  {
    System.out.println("lost focus");
    setForeground(Color.red);
    return true;
  }
//////////////////////////////////////////////////////////////////
 public boolean mouseDown(Event e, int x, int y)
  {
    System.out.println("mouse down");
    try {
      URL url=new URL(qpdb.rcsb_explore_url + (qpdb.rcsb_explore_url.endsWith("=") ? "" : "=") + qpdb.pdb_file);
      qpdb.getAppletContext().showDocument(url, qpdb.pdb_file);
      return true;
    }
    catch (MalformedURLException ex) {
    }
    return true;
  }
//////////////////////////////////////////////////////////////////
}
  */
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class LogoCanvas extends Canvas 
{
  QpdbFrame qpdb;

//////////////////////////////////////////////////////////////////
  LogoCanvas(QpdbFrame qpdb_)
  {
    super();
    qpdb=qpdb_;
  }
//////////////////////////////////////////////////////////////////
public void paint(Graphics g)
  {
    Dimension d=this.size();
    g.clearRect(0, 0, d.width, d.height);

    if(qpdb.sdsc_logo==null) 
      {
	try
	  {
	    URL url=new URL(qpdb.html_url+"/sdsc_logo.gif");
	    qpdb.sdsc_logo=qpdb.applet.getImage(url);
	  }
	catch (MalformedURLException e)
	  {
	  }
      }
	
    g.drawImage(qpdb.sdsc_logo, 0, 0, this); 
    
    //Font f=new Font("Helvetica", Font.PLAIN, 8);
    //g.setFont(f);
    g.drawString("Applet QuickPDB v1.1 (C) 1996-1998 SDSC, by Ilya Shindyalov & Phil Bourne", 30, d.height-2);
  }
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class SeqCanvas extends Canvas
{
  SeqPanel seqPanel;
//////////////////////////////////////////////////////////////////
public SeqCanvas(SeqPanel seqPanel_) 
  {
    super();
    seqPanel=seqPanel_;
  }
//////////////////////////////////////////////////////////////////
public void paint(Graphics g)
  {
    seqPanel.paint(g);
  }
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class SeqPanel extends Panel
{
  Canvas seqCanvas;
  Scrollbar vbar;
  QpdbFrame qpdb;
  int xold, yold, xnew, ynew;
  boolean rectOn;
  int seqPosY, seqSizeX, seqSizeY;
  int seqCharX, seqCharY;
  int seqpSizeX, seqpSizeY;
//////////////////////////////////////////////////////////////////
public SeqPanel(QpdbFrame qpdb_)
  {
    super();
    rectOn=false;
    qpdb=qpdb_;
    seqCharX=8; seqCharY=14;
    seqCanvas=new SeqCanvas(this);
    vbar=new Scrollbar(Scrollbar.VERTICAL);
    this.setLayout(new BorderLayout(0, 0));
    this.add("Center", seqCanvas);
    this.add("East", vbar);
  }
//////////////////////////////////////////////////////////////////
public void paint(Graphics g)
  {
    Dimension dseq=seqCanvas.size();
    Image imbuf=seqCanvas.createImage(dseq.width, dseq.height);
    Graphics gseq=imbuf.getGraphics();
    Graphics gseq_=seqCanvas.getGraphics();
    Color bg=seqCanvas.getBackground();

    int nSeqChar_ = ((dseq.width - qpdb.seqCharLM) / seqCharX) / 10 * 10;
    
    if(nSeqChar_ != qpdb.nSeqChar) {
      qpdb.nSeqChar = nSeqChar_;
      qpdb.nSeqPos = 0;
      for(int i = 0; i < qpdb.nEnt; i++) 
	qpdb.nSeqPos += (qpdb.nSE[i] + 1) / qpdb.nSeqChar + 1;
      qpdb.seqPosEnt = new int [qpdb.nSeqPos];
      qpdb.seqPosSE = new int [qpdb.nSeqPos];
      qpdb.nSeqPos = 0;
      for(int i = 0; i < qpdb.nEnt; i++) {
	for(int j = 0; j < qpdb.nSE[i]; j += qpdb.nSeqChar) {
	  qpdb.seqPosEnt[qpdb.nSeqPos] = i;
	  qpdb.seqPosSE[qpdb.nSeqPos] = j;
	  qpdb.nSeqPos++;
	}
      }
    }
    gseq.setColor(bg);
    gseq.fillRect(0, 0, dseq.width, dseq.height);
    seqSizeX=dseq.width/seqCharX;
    seqSizeY=dseq.height/seqCharY;
    if(rectOn)
      {
	gseq.setColor(Color.white);
	gseq.fillRect(xold + qpdb.seqCharLM, yold+3, 
		      Math.min(xnew, qpdb.nSeqChar*seqCharX) - xold,
		      Math.min(ynew, (qpdb.nSeqPos-seqPosY-1)*seqCharY) - yold
		      +seqCharY+1);
      }

    if(qpdb.nEnt==0) 
      {
	vbar.setValues(0, 1, 0, 1);
	gseq_.drawImage(imbuf, 0, 0, seqCanvas);
	return;
      }
    Color oldColor=Color.white; int i, j, ii, jj;
    
    for(i = seqPosY, ii=0; i < qpdb.nSeqPos && ii<seqSizeY; i++, ii++) {
      int iE = qpdb.seqPosEnt[i];
      int iS = qpdb.seqPosSE[i];
      gseq.setColor(Color.white);
      oldColor=Color.white;
      gseq.drawString(qpdb.entName[iE], 5, ii*seqCharY+seqCharY);

      String pos = "   "+(iS+1);
      pos = pos.substring(pos.length()-4);
      gseq.drawString(pos, 60, ii*seqCharY+seqCharY);

      for(j = iS, jj=0; j < qpdb.nSE[iE] && jj < qpdb.nSeqChar; j++, jj++) {
	if(oldColor!=qpdb.seColors[iE][j]) 
	  {
	    gseq.setColor(qpdb.seColors[iE][j]);
	    oldColor=qpdb.seColors[iE][j];
	  }
	gseq.drawString(qpdb.seqLine[iE].substring(j, j+1), 
			qpdb.seqCharLM+jj*seqCharX, ii*seqCharY+seqCharY);
      }
    }

    vbar.setValues(seqPosY, seqSizeY, 0, qpdb.nSeqPos);
    gseq_.drawImage(imbuf, 0, 0, seqCanvas);
  }
//////////////////////////////////////////////////////////////////
public void setPosView(int x, int y)
  {
    Graphics g=qpdb.seq_pos.getGraphics();
    Dimension d=qpdb.seq_pos.size();
    seqpSizeX=d.width; seqpSizeY=d.height;
    g.clearRect(0, 0, seqpSizeX, seqpSizeY);
    if(qpdb.nEnt!=0) 
      {
	int xpos=(x - qpdb.seqCharLM) / seqCharX + 
	  qpdb.seqPosSE[seqPosY + (y - 2) / seqCharY] + 1;
	int ypos= qpdb.seqPosEnt[seqPosY + (y - 2) / seqCharY];
	if(ypos>=0 && ypos<qpdb.nEnt && xpos>0 && xpos <= qpdb.nSE[ypos] 
	   && xpos <= qpdb.seqPosSE[seqPosY + (y - 2) / seqCharY] + 
	   qpdb.nSeqChar)
	  g.drawString("Cursor at "+qpdb.entName[ypos]+" "+xpos+
		       qpdb.seqLine[ypos].substring(xpos-1,xpos), 5, 13);
      }
  }
//////////////////////////////////////////////////////////////////
public boolean mouseDown(Event e, int x, int y)
  {
    xold=(x-qpdb.seqCharLM)/seqCharX*seqCharX; yold=y/seqCharY*seqCharY;
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean mouseMove(Event e, int x, int y)
  {
    setPosView(x, y);
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean mouseDrag(Event e, int x, int y)
  {
    if(qpdb.nEnt!=0) 
      {
	setPosView(x, y);
	rectOn=true;
	xnew=(x-qpdb.seqCharLM)/seqCharX*seqCharX; ynew=y/seqCharY*seqCharY;
	if(xold!=xnew || yold!=ynew) this.repaint();
      }
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean mouseUp(Event e, int x, int y)
  {
    xnew=(x-qpdb.seqCharLM)/seqCharX*seqCharX; ynew=y/seqCharY*seqCharY;
    rectOn=false;
    if(xnew==xold) xnew+=seqCharX;
    if(xold >= 0 && yold/seqCharY+seqPosY < qpdb.nSeqPos) {
      for(int i = yold/seqCharY+seqPosY; i<=Math.min(ynew/seqCharY+seqPosY, qpdb.nSeqPos); i++) {
	int iE = qpdb.seqPosEnt[i];
	int iS = qpdb.seqPosSE[i];
	for(int j=xold/seqCharX+iS; j<xnew/seqCharX+iS && j<qpdb.nSE[iE]; j++)
	  qpdb.seColors[iE][j] = qpdb.seColors[iE][j] == qpdb.currentColor ?
	    qpdb.initColor : qpdb.currentColor;
      }
      this.repaint();
      qpdb.struc.paint(qpdb.struc.getGraphics());
    }
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean handleEvent(Event e) 
  {
    if (e.target == vbar) 
      {
	switch(e.id) 
	  {
	  case Event.SCROLL_LINE_UP:  
	  case Event.SCROLL_PAGE_UP:  
	  case Event.SCROLL_LINE_DOWN: 
	  case Event.SCROLL_PAGE_DOWN: 
	  case Event.SCROLL_ABSOLUTE:  
	    seqPosY=((Integer)e.arg).intValue();    
	    break;
	  }
	repaint();
	return true;
      }
    return super.handleEvent(e);
  }
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
class StrucCanvas extends Canvas
{
  int mX0, mY0, mX1, mY1;
  QpdbFrame qpdb;
  Image imbuf, imbuf_left, imbuf_right;
  Dimension imbufDim, imbufDimLR;
  int click_ent, click_pos;
//////////////////////////////////////////////////////////////////
  StrucCanvas(QpdbFrame qpdb_)
  {
    super();
    qpdb=qpdb_;
    imbuf=null; 
    imbuf_left=null;
    imbufDim = new Dimension(-1, -1);
  }
//////////////////////////////////////////////////////////////////
public void paint(Graphics gstruc_canvas)
  {
    Dimension dstruc=this.size();

    if(!imbufDim.equals(dstruc)) qpdb.scale();

    click_ent = -1;
    click_pos = -1;
    int d_min = 10000;

    if(imbuf == null || !imbufDim.equals(dstruc)) {
      imbuf=this.createImage(dstruc.width, dstruc.height);
      imbufDim = dstruc;
    }
    if(qpdb.stereo && (imbuf_left == null || !imbufDimLR.equals(dstruc))) {
      imbuf_left=this.createImage(dstruc.width/2-10, dstruc.height);
      imbuf_right=this.createImage(dstruc.width/2-10, dstruc.height);
      imbufDimLR = dstruc;
    }
    Graphics gstruc, gstruc_=null;
    if(qpdb.stereo)
      {
	gstruc=imbuf_left.getGraphics();
	gstruc_=imbuf_right.getGraphics();
      }
    else
      {
	gstruc=imbuf.getGraphics();
      }
    Color bg=this.getBackground();

    gstruc.setColor(bg);
    if(qpdb.stereo) gstruc_.setColor(bg);

    double c11, c12, c13, c21, c22, c23, c31, c32, c33, dot[]=new double[3], 
      dot_x0, dot_y0, dot_z0, shiftx=qpdb.shiftx, 
      shifty=qpdb.stereo?qpdb.shifty*2.0:qpdb.shifty, 
      scale=qpdb.stereo?qpdb.scale/2.0:qpdb.scale, 
      stereo_cos=0.9961947, stereo_sin=0.087155743; 

    int i;
    c11=qpdb.cc[0][0]; c12=qpdb.cc[0][1]; c13=qpdb.cc[0][2];
    c21=qpdb.cc[1][0]; c22=qpdb.cc[1][1]; c23=qpdb.cc[1][2];
    c31=qpdb.cc[2][0]; c32=qpdb.cc[2][1]; c33=qpdb.cc[2][2];
    
    gstruc.fillRect(0, 0, dstruc.width, dstruc.height);
    if(qpdb.stereo) gstruc_.fillRect(0, 0, dstruc.width, dstruc.height);
    
    if(qpdb.nEnt==0) {
      if(gstruc_canvas != null)
	gstruc_canvas.drawImage(imbuf, 0, 0, this);
      return;
    }

    Color oldColor=Color.white;
    
    boolean brake_flag=true;
    int ix1=0, iy1=0, ix2, iy2, j;
    for(int istereo=0; istereo<(qpdb.stereo?2:1); istereo++)
      {
	for(int iEnt=0; iEnt<qpdb.nEnt; iEnt++)
	  {
	    brake_flag=true;
	    for(i=0; i<qpdb.nSE[iEnt]; i++)
	      {
		if(qpdb.xyz[iEnt][i][0]>80000.0) 
		  {
		    brake_flag=true;
		    continue;
		  }
		dot[0]=qpdb.xyz[iEnt][i][0]; 
		dot[1]=qpdb.xyz[iEnt][i][1]; 
		dot[2]=qpdb.xyz[iEnt][i][2];
		dot_x0=dot[0]*c11+dot[1]*c12+dot[2]*c13;
		dot_y0=dot[0]*c21+dot[1]*c22+dot[2]*c23;
		if(istereo==1) 
		  {
		    dot_z0=dot[0]*c31+dot[1]*c32+dot[2]*c33;
		    dot_x0=dot_x0*stereo_cos-dot_z0*stereo_sin;
		  }

		if(brake_flag)
		  {
		    ix1=(int)((dot_x0+shiftx)*scale);
		    iy1=(int)((dot_y0+shifty)*scale);
		    oldColor=qpdb.seColors[iEnt][i];
		    if(istereo==0) gstruc.setColor(oldColor);
		    else gstruc_.setColor(oldColor);
		    brake_flag=false;
		  }
		else
		  {
		    ix2=(int)((dot_x0+shiftx)*scale); 
		    iy2=(int)((dot_y0+shifty)*scale);
		    if(oldColor!=qpdb.seColors[iEnt][i])
		      {
			if(istereo==0) gstruc.drawLine(ix1, iy1, (ix1+ix2)/2, 
						       (iy1+iy2)/2);
			else gstruc_.drawLine(ix1, iy1, (ix1+ix2)/2, 
						       (iy1+iy2)/2);
			oldColor=qpdb.seColors[iEnt][i];
			if(istereo==0) gstruc.setColor(oldColor);
			else gstruc_.setColor(oldColor);
			if(istereo==0) gstruc.drawLine((ix1+ix2)/2, 
						       (iy1+iy2)/2, ix2, iy2);
			else gstruc_.drawLine((ix1+ix2)/2, 
					      (iy1+iy2)/2, ix2, iy2);
		      }
		    else
		      {
			if(istereo==0) 
			  gstruc.drawLine(ix1, iy1, ix2, iy2);
			else
			  gstruc_.drawLine(ix1, iy1, ix2, iy2);
		      }
		    if(gstruc_canvas == null) {
		      int d = Math.abs(mX0 - ix1) + Math.abs(mY0 - iy1);
		      if(d < d_min) {
			d_min = d;
			click_ent = iEnt;
			click_pos = i;
		      }
		      d = Math.abs(mX0 - ix2) + Math.abs(mY0 - iy2);
		      if(d < d_min) {
			d_min = d;
			click_ent = iEnt;
			click_pos = i + 1;
		      }
		    }
		    ix1=ix2; iy1=iy2;
		  }
	      }
	  }
      }

    if(gstruc_canvas != null) {
      if(qpdb.stereo) {
	gstruc_canvas.drawImage(imbuf_left, 0, 0, dstruc.width/2-10, 
				dstruc.height, this);
	gstruc_canvas.drawImage(imbuf_right, dstruc.width/2, 0, 
				dstruc.width/2-10, dstruc.height, this);
      }
      else {
	gstruc_canvas.drawImage(imbuf, 0, 0, this);
      }
    }
  }
//////////////////////////////////////////////////////////////////
public boolean mouseMove(Event e, int x, int y)
  {
    mX0 = x; mY0 = y;
    paint(null);
    if(click_ent != -1) {
      Graphics g=qpdb.seq_pos.getGraphics();
      Dimension d=qpdb.seq_pos.size();
      g.clearRect(0, 0, d.width, d.height);
      g.drawString("Cursor at "+qpdb.entName[click_ent]+" "+click_pos+
		   qpdb.seqLine[click_ent].substring(click_pos-1,click_pos), 
		   5, 13);
    }
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean mouseDown(Event e, int x, int y)
  {
    mX0=x; mY0=y;
    if(e.clickCount > 1) {
      paint(null);
      if(click_ent != -1)
      qpdb.seColors[click_ent][click_pos - 1] = 
	qpdb.seColors[click_ent][click_pos - 1] == qpdb.currentColor ?
	 qpdb.initColor : qpdb.currentColor;
      qpdb.seq.repaint();
      qpdb.struc.paint(qpdb.struc.getGraphics());
      
    }
    return true;
  }
//////////////////////////////////////////////////////////////////
public boolean mouseDrag(Event e, int x, int y)
  {
    int mX1=x, mY1=y;
    boolean needRefresh=false;
    int mouse_mask=0;
    if(e.modifiers==Event.META_MASK || e.modifiers==Event.SHIFT_MASK) 
      mouse_mask=1;
    if(e.modifiers==Event.ALT_MASK || e.modifiers==Event.CTRL_MASK) 
      mouse_mask=2;

    if(qpdb.mouseStatus==0 && mouse_mask==0)
      {
	double m[][]=new double [3][3];
	double rotY=(mX1-mX0)/900.0*Math.PI;
	double rotX=(mY1-mY0)/900.0*Math.PI;
	if(mX1!=mX0)
	  {
	    m[0][0]=Math.cos(rotY); m[0][1]=0.0; m[0][2]=-Math.sin(rotY);
	    m[1][0]=0.0;            m[1][1]=1.0; m[1][2]=0.0;
	    m[2][0]=Math.sin(rotY); m[2][1]=0.0; m[2][2]=Math.cos(rotY);
	    rot(m, qpdb.cc);
	    mX0=mX1;
	    needRefresh=true;
	  }
	if(mY1!=mY0)
	  {
	    m[0][0]=1.0; m[0][1]=0.0;              m[0][2]=0.0;
	    m[1][0]=0.0; m[1][1]=Math.cos(rotX);  m[1][2]=-Math.sin(rotX);
	    m[2][0]=0.0; m[2][1]=Math.sin(rotX);  m[2][2]=Math.cos(rotX);
	    rot(m, qpdb.cc);
	    mY0=mY1;
	    needRefresh=true;
	  }
      }
    if((qpdb.mouseStatus==1 && mouse_mask==0) || mouse_mask==1)
      {
	if(mX1!=mX0)
	  {
	    qpdb.shiftx+=(mX1-mX0)/qpdb.scale;
	    mX0=mX1;
	    needRefresh=true;
	  }
	if(mY1!=mY0)
	  {
	    qpdb.shifty+=(mY1-mY0)/qpdb.scale;
	    mY0=mY1;
	    needRefresh=true;
	  }
      }
    
    if((qpdb.mouseStatus==2 && mouse_mask==0) || mouse_mask==2)
      {
	if(mX1!=mX0)
	  {
	    if(mX1<mX0)
	      {
		qpdb.scale*=(1.0+(mX1-mX0)*0.01);
		qpdb.shiftx/=(1.0+(mX1-mX0)*0.01);
		qpdb.shifty/=(1.0+(mX1-mX0)*0.01);
	      }
	    if(mX1>mX0)
	      {
		qpdb.scale/=(1.0+(mX0-mX1)*0.01);
		qpdb.shiftx*=(1.0+(mX0-mX1)*0.01);
		qpdb.shifty*=(1.0+(mX0-mX1)*0.01);
	      }
	    mX0=mX1;
	    needRefresh=true;
	  }
      }
  
    if(needRefresh) 
      {
	this.paint(this.getGraphics());
      }
  
    return true;
  }
//////////////////////////////////////////////////////////////////
  void rot(double m1[][], double m2[][])
  {
    double m3[][]=new double [3][3], m; int i,j,k;
    for(i=0; i<3; i++)
      for(j=0; j<3; j++)
	{
	  m=0.0;
	  for(k=0; k<3; k++) m+=(m1[i][k]*m2[k][j]);
	  m3[i][j]=m;
	}
    for(i=0; i<3; i++)
      for(j=0; j<3; j++)  m2[i][j]=m3[i][j];
  }
//////////////////////////////////////////////////////////////////
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

