ui/src/main/java/ucar/nc2/ui/grid/ColorScale.java
public void setMinMax(double min, double max) {
    this.min = min;
    this.max = max;
    interval = (max - min) / (ncolors - 2);

    // set edges
    for (int i = 0; i < ncolors; i++)
      edge[i] = min + i * interval;

    lm.sendEvent(new PropertyChangeEvent(this, "ColorScaleLimits", null, this));
  }


  /**
   * This is an optimization for counting the number of colors in each interval.
   * the histpogram is populated by calls to getIndexFromValue().
   *
   * @return the index with the maximum histogram count.
   */
  public int getHistMax() {
    int max = 0, maxi = 0;
    for (int i = 0; i <= ncolors; i++)
      if (hist[i] > max) {
        max = hist[i];
        maxi = i;
      }
    return maxi;
  }

  /**
   * reset the histogram.
   */
  public void resetHist() {
    for (int i = 0; i <= ncolors; i++)
      hist[i] = 0;
  }

  public String toString() {
    return name;
  }

  public Object clone() {
    ColorScale cl = new ColorScale(name, colors);
    /*try {
      cl = (ColorScale) super.clone();
    } catch(CloneNotSupportedException e) {
      return null;
    } // ignore

    // non primitive fields must be cloned separately
    cl.name = new String(name);
    cl.set(this);
    cl.construct();  */
    return (Object) cl;
  }

  /////////// private ////////////////////

  // this is for editing a colorscale
  private void editModeBegin() {
    Color [] editColors = new Color[ ncolors];
    System.arraycopy(colors, 0, editColors, 0, ncolors);
    useColors = editColors;
  }

  private void editModeEnd(boolean accept) {
    if (accept) {
      System.arraycopy(useColors, 0, colors, 0, ncolors);
    }
    useColors = colors;
  }

  private void setColor(int i, Color c) {
    if (i >= 0 && i < ncolors)
      useColors[i] = c;
  }

  /* private void set( ColorScale cs) {
   set(cs.getColors());
 } */
  private void setColors(Color[] c) {
    ncolors = c.length;
    colors = new Color[ ncolors];
    System.arraycopy(c, 0, colors, 0, ncolors);
    edge = new double[ ncolors];
    hist = new int[ ncolors + 1];
    useColors = colors;        // ??
  }

  // serialization
  private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
    s.readInt();
    this.name = s.readUTF();
    this.colors = (Color[]) s.readObject();
    this.ncolors = colors.length;
    constructTransient();
  }

  private void writeObject(ObjectOutputStream s) throws IOException {
    s.writeInt(objectVersion);
    s.writeUTF(this.name);
    s.writeObject(this.colors);
  }

  // heres the swing component part of a ColorScale: static so its not part of serialization
  // originally designed to allow popup editor to change colors; this has been disabled; all
  // changes made by COlorManager. design could be cleaned up, but maybe I want that back later?
  public static class Panel extends JPanel {
    private int type;

    private int size = 50;
    private ColorScale cs;
    private JLabel unitLabel = new JLabel("unit", SwingConstants.CENTER);
    private JPanel lpanel;

    private boolean editable = false;
    private int selected = -1;

    private int nColorInterval;
    private String[] label;
    private boolean useLabel = true;
    private FontUtil.StandardFont sf = FontUtil.getStandardFont(10);

    public Panel(Component parent) {
      this(parent, ColorScale.VERTICAL, null);
    }

    public Panel(Component parent, ColorScale cscale) {
      this(parent, ColorScale.VERTICAL, cscale);
    }

    public Panel(Component parent, int type, ColorScale cscale) {
      this.cs = (cscale == null) ? new ColorScale("default") : cscale;
      this.type = type;

      if (type == ColorScale.VERTICAL) {
        setPreferredSize(new Dimension(size, 400));
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      } else {
        setPreferredSize(new Dimension(400, size));
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
      }

      setListener();

      nColorInterval = cs.getNumColors();
      for (int i = 0; i < nColorInterval; i++) {
        ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
        add(intv);
      }
      lpanel = new JPanel();
      lpanel.add(unitLabel);
      //unitLabel.setBorder( new javax.swing.border.EtchedBorder());
      if (type == ColorScale.VERTICAL)
        lpanel.setPreferredSize(new Dimension(size, 0));
      else
        lpanel.setPreferredSize(new Dimension(0, size));
      add(lpanel);

      label = new String[ nColorInterval];
      calcLabels();

      /* creates a popup men, attaches it to this Panel
     PopupMenu popupMenu = new PopupMenu(this, "options");
     popupMenu.add("Edit", new AbstractAction() {
       public void actionPerformed(ActionEvent e) {
         System.out.println("popup edit action");
         dialog.show();
       }
     }); */

    }

    private void calcLabels() {
      label[0] = "<" + Format.d(cs.getEdge(0), sigfig);
      for (int i = 1; i < nColorInterval - 1; i++) {
        label[i] = Format.d(cs.getEdge(i), sigfig);
      }
      label[nColorInterval - 1] = ">" + Format.d(cs.getEdge(nColorInterval - 2), sigfig);
    }

    private void setListener() {
      // listen for changes so we can redraw
      cs.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
        public void propertyChange(java.beans.PropertyChangeEvent e) {
          if (e.getPropertyName().equals("ColorScaleLimits"))
            calcLabels();
          repaint();
        }
      });
    }

    public ColorScale getColorScale() {
      return cs;
    }

    // change the current cscale
    public void setColorScale(ColorScale cscale) {
      if (nColorInterval != cscale.getNumColors()) {
        removeAll();
        nColorInterval = cscale.getNumColors();
        label = new String[ nColorInterval];
        for (int i = 0; i < nColorInterval; i++) {
          ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
          add(intv);
          label[i] = "none";
        }
        add(lpanel);
        revalidate();
      }

      this.cs = cscale;
      setListener();
      calcLabels();
      repaint();
    }

    // set existing colorscale to have new colors
    public void setColors(Color[] c) {
      if (nColorInterval != c.length) {
        removeAll();
        nColorInterval = c.length;
        label = new String[ nColorInterval];
        for (int i = 0; i < nColorInterval; i++) {
          ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
          add(intv);
          label[i] = "none";
        }
        add(lpanel);
        revalidate();
      }

      cs.setColors(c);
      cs.editModeBegin(); // again

      if (debugColors) {
        for (int i = 0; i < cs.getNumColors(); i++)
          System.out.println(cs.getColor(i));
      }
      calcLabels();
      repaint();
    }


    public void setColor(Color c) {
      cs.setColor(selected, c);
    }

    //public void setEditable( boolean b) { editable = b; }
    public void setEditMode(boolean on, boolean accept) {
      if (on) {
        editable = true;
        cs.editModeBegin();
      } else {
        cs.editModeEnd(accept);
        if (accept)
          setColorScale(cs);
        selected = -1;
        editable = false;
      }
      repaint();
    }

    public void setSelected(int i) {
      selected = i;
    }

    public void setShowText(boolean b) {
      useLabel = b;
    }

    /*private void edit(int which) {
      if (!editable)
        return;
      selected = which;
      repaint();
      cs.setEditMode(true);
      //dialog.show();
    }*/
    public void setUnitString(String s) {
      unitLabel.setText(s);
      //System.out.println("new text = "+s);
      //unitLabel.repaint(s);
    }

    public void print(Graphics2D g, double x, double y, double width, double height) {
      int n = cs.getNumColors();
      double size = (type == ColorScale.VERTICAL) ? height / n : width / n;
      int count = 0;
      for (int i = 0; i < getComponentCount(); i++) {
        Component c = getComponent(i);
        if (c instanceof ColorInterval) {
          ColorInterval intv = (ColorInterval) c;
          if (type == ColorScale.VERTICAL)
            intv.printV(g, (int) x, (int) (y + count * size), (int) width, (int) size);
          else {
            double xpos = x + width - (count + 1) * size;
            intv.printH(g, (int) xpos, (int) y, (int) size, (int) height);
          }
          count++;
        }
      }
    }

    /* private class OkListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.accept();
        repaint();
      }
    }  // end inner class OkListener

    private class CancelListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.cancel();
        repaint();
      }
    } // end inner class CancelListener  */

    private class ColorInterval extends JComponent {
      private int rank;

      ColorInterval(int r) {
        this.rank = r;
        //setPreferredSize( new Dimension(40,40));
        addMouseListener(new MouseAdapter() {
          public void mousePressed(MouseEvent e) {
            if (editable) {
              selected = rank;
              Panel.this.repaint();
            }
          }
        });
      }

      public void printV(Graphics2D g, int x, int y, int width, int height) {
        int textSize = 15; // LOOK : neeed to calculate this

        g.setColor(cs.getColor(rank));
        g.fillRect(x, y + textSize, width, height - textSize);

        //g.setColor( Color.black);
        //g.drawRect( x, y+textSize, width, height-textSize);

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          g.drawString(label[rank], x + 3, y + 10);
        }
      }

      public void printH(Graphics2D g, int x, int y, int width, int height) {
        int textSize = 15; // LOOK : neeed to calculate this

        g.setColor(cs.getColor(rank));
        g.fillRect(x, y + textSize, width, height - 2 * textSize);

        g.setColor(Color.white);
        g.drawRect(x, y + textSize, width, height - 2 * textSize);

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          if (rank % 2 == 0) // even
            g.drawString(label[rank], x, y + textSize);
          else
            g.drawString(label[rank], x, y + height);
        }
      }

      public void paintComponent(Graphics g) {
        Rectangle b = getBounds();

        g.setColor(cs.getColor(rank));
        g.fillRect(0, 0, b.width - 1, b.height - 1);

        g.setColor((selected == rank) ? Color.magenta : Color.black);
        g.drawRect(0, 0, b.width - 1, b.height - 1);

        if (selected == rank) {
          g.drawLine(0, 0, b.width, b.height);
          g.drawLine(0, b.height, b.width, 0);
        }

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          g.drawString(label[rank], 3, 10);
        }
      }
    } // end inner class ColorInterval


  } // end inner class ColorScale.Panel
}
public void setMinMax(double min, double max) {
    this.min = min;
    this.max = max;
    interval = (max - min) / (ncolors - 2);

    // set edges
    for (int i = 0; i < ncolors; i++)
      edge[i] = min + i * interval;

    lm.sendEvent(new PropertyChangeEvent(this, "ColorScaleLimits", null, this));
  }


  /**
   * This is an optimization for counting the number of colors in each interval.
   * the histpogram is populated by calls to getIndexFromValue().
   *
   * @return the index with the maximum histogram count.
   */
  public int getHistMax() {
    int max = 0, maxi = 0;
    for (int i = 0; i <= ncolors; i++)
      if (hist[i] > max) {
        max = hist[i];
        maxi = i;
      }
    return maxi;
  }

  /**
   * reset the histogram.
   */
  public void resetHist() {
    for (int i = 0; i <= ncolors; i++)
      hist[i] = 0;
  }

  public String toString() {
    return name;
  }

  public Object clone() {
    ColorScale cl = new ColorScale(name, colors);
    /*try {
      cl = (ColorScale) super.clone();
    } catch(CloneNotSupportedException e) {
      return null;
    } // ignore

    // non primitive fields must be cloned separately
    cl.name = new String(name);
    cl.set(this);
    cl.construct();  */
    return (Object) cl;
  }

  /////////// private ////////////////////

  // this is for editing a colorscale
  private void editModeBegin() {
    Color [] editColors = new Color[ ncolors];
    System.arraycopy(colors, 0, editColors, 0, ncolors);
    useColors = editColors;
  }

  private void editModeEnd(boolean accept) {
    if (accept) {
      System.arraycopy(useColors, 0, colors, 0, ncolors);
    }
    useColors = colors;
  }

  private void setColor(int i, Color c) {
    if (i >= 0 && i < ncolors)
      useColors[i] = c;
  }

  /* private void set( ColorScale cs) {
   set(cs.getColors());
 } */
  private void setColors(Color[] c) {
    ncolors = c.length;
    colors = new Color[ ncolors];
    System.arraycopy(c, 0, colors, 0, ncolors);
    edge = new double[ ncolors];
    hist = new int[ ncolors + 1];
    useColors = colors;        // ??
  }

  // serialization
  private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
    s.readInt();
    this.name = s.readUTF();
    this.colors = (Color[]) s.readObject();
    this.ncolors = colors.length;
    constructTransient();
  }

  private void writeObject(ObjectOutputStream s) throws IOException {
    s.writeInt(objectVersion);
    s.writeUTF(this.name);
    s.writeObject(this.colors);
  }

  // heres the swing component part of a ColorScale: static so its not part of serialization
  // originally designed to allow popup editor to change colors; this has been disabled; all
  // changes made by COlorManager. design could be cleaned up, but maybe I want that back later?
  public static class Panel extends JPanel {
    private int type;

    private int size = 50;
    private ColorScale cs;
    private JLabel unitLabel = new JLabel("unit", SwingConstants.CENTER);
    private JPanel lpanel;

    private boolean editable = false;
    private int selected = -1;

    private int nColorInterval;
    private String[] label;
    private boolean useLabel = true;
    private FontUtil.StandardFont sf = FontUtil.getStandardFont(10);

    public Panel(Component parent) {
      this(parent, ColorScale.VERTICAL, null);
    }

    public Panel(Component parent, ColorScale cscale) {
      this(parent, ColorScale.VERTICAL, cscale);
    }

    public Panel(Component parent, int type, ColorScale cscale) {
      this.cs = (cscale == null) ? new ColorScale("default") : cscale;
      this.type = type;

      if (type == ColorScale.VERTICAL) {
        setPreferredSize(new Dimension(size, 400));
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      } else {
        setPreferredSize(new Dimension(400, size));
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
      }

      setListener();

      nColorInterval = cs.getNumColors();
      for (int i = 0; i < nColorInterval; i++) {
        ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
        add(intv);
      }
      lpanel = new JPanel();
      lpanel.add(unitLabel);
      //unitLabel.setBorder( new javax.swing.border.EtchedBorder());
      if (type == ColorScale.VERTICAL)
        lpanel.setPreferredSize(new Dimension(size, 0));
      else
        lpanel.setPreferredSize(new Dimension(0, size));
      add(lpanel);

      label = new String[ nColorInterval];
      calcLabels();

      /* creates a popup men, attaches it to this Panel
     PopupMenu popupMenu = new PopupMenu(this, "options");
     popupMenu.add("Edit", new AbstractAction() {
       public void actionPerformed(ActionEvent e) {
         System.out.println("popup edit action");
         dialog.show();
       }
     }); */

    }

    private void calcLabels() {
      label[0] = "<" + Format.d(cs.getEdge(0), sigfig);
      for (int i = 1; i < nColorInterval - 1; i++) {
        label[i] = Format.d(cs.getEdge(i), sigfig);
      }
      label[nColorInterval - 1] = ">" + Format.d(cs.getEdge(nColorInterval - 2), sigfig);
    }

    private void setListener() {
      // listen for changes so we can redraw
      cs.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
        public void propertyChange(java.beans.PropertyChangeEvent e) {
          if (e.getPropertyName().equals("ColorScaleLimits"))
            calcLabels();
          repaint();
        }
      });
    }

    public ColorScale getColorScale() {
      return cs;
    }

    // change the current cscale
    public void setColorScale(ColorScale cscale) {
      if (nColorInterval != cscale.getNumColors()) {
        removeAll();
        nColorInterval = cscale.getNumColors();
        label = new String[ nColorInterval];
        for (int i = 0; i < nColorInterval; i++) {
          ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
          add(intv);
          label[i] = "none";
        }
        add(lpanel);
        revalidate();
      }

      this.cs = cscale;
      setListener();
      calcLabels();
      repaint();
    }

    // set existing colorscale to have new colors
    public void setColors(Color[] c) {
      if (nColorInterval != c.length) {
        removeAll();
        nColorInterval = c.length;
        label = new String[ nColorInterval];
        for (int i = 0; i < nColorInterval; i++) {
          ColorInterval intv = new ColorInterval(nColorInterval - i - 1);
          add(intv);
          label[i] = "none";
        }
        add(lpanel);
        revalidate();
      }

      cs.setColors(c);
      cs.editModeBegin(); // again

      if (debugColors) {
        for (int i = 0; i < cs.getNumColors(); i++)
          System.out.println(cs.getColor(i));
      }
      calcLabels();
      repaint();
    }


    public void setColor(Color c) {
      cs.setColor(selected, c);
    }

    //public void setEditable( boolean b) { editable = b; }
    public void setEditMode(boolean on, boolean accept) {
      if (on) {
        editable = true;
        cs.editModeBegin();
      } else {
        cs.editModeEnd(accept);
        if (accept)
          setColorScale(cs);
        selected = -1;
        editable = false;
      }
      repaint();
    }

    public void setSelected(int i) {
      selected = i;
    }

    public void setShowText(boolean b) {
      useLabel = b;
    }

    /*private void edit(int which) {
      if (!editable)
        return;
      selected = which;
      repaint();
      cs.setEditMode(true);
      //dialog.show();
    }*/
    public void setUnitString(String s) {
      unitLabel.setText(s);
      //System.out.println("new text = "+s);
      //unitLabel.repaint(s);
    }

    public void print(Graphics2D g, double x, double y, double width, double height) {
      int n = cs.getNumColors();
      double size = (type == ColorScale.VERTICAL) ? height / n : width / n;
      int count = 0;
      for (int i = 0; i < getComponentCount(); i++) {
        Component c = getComponent(i);
        if (c instanceof ColorInterval) {
          ColorInterval intv = (ColorInterval) c;
          if (type == ColorScale.VERTICAL)
            intv.printV(g, (int) x, (int) (y + count * size), (int) width, (int) size);
          else {
            double xpos = x + width - (count + 1) * size;
            intv.printH(g, (int) xpos, (int) y, (int) size, (int) height);
          }
          count++;
        }
      }
    }

    /* private class OkListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.accept();
        repaint();
      }
    }  // end inner class OkListener

    private class CancelListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.cancel();
        repaint();
      }
    } // end inner class CancelListener  */

    private class ColorInterval extends JComponent {
      private int rank;

      ColorInterval(int r) {
        this.rank = r;
        //setPreferredSize( new Dimension(40,40));
        addMouseListener(new MouseAdapter() {
          public void mousePressed(MouseEvent e) {
            if (editable) {
              selected = rank;
              Panel.this.repaint();
            }
          }
        });
      }

      public void printV(Graphics2D g, int x, int y, int width, int height) {
        int textSize = 15; // LOOK : neeed to calculate this

        g.setColor(cs.getColor(rank));
        g.fillRect(x, y + textSize, width, height - textSize);

        //g.setColor( Color.black);
        //g.drawRect( x, y+textSize, width, height-textSize);

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          g.drawString(label[rank], x + 3, y + 10);
        }
      }

      public void printH(Graphics2D g, int x, int y, int width, int height) {
        int textSize = 15; // LOOK : neeed to calculate this

        g.setColor(cs.getColor(rank));
        g.fillRect(x, y + textSize, width, height - 2 * textSize);

        g.setColor(Color.white);
        g.drawRect(x, y + textSize, width, height - 2 * textSize);

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          if (rank % 2 == 0) // even
            g.drawString(label[rank], x, y + textSize);
          else
            g.drawString(label[rank], x, y + height);
        }
      }

      public void paintComponent(Graphics g) {
        Rectangle b = getBounds();

        g.setColor(cs.getColor(rank));
        g.fillRect(0, 0, b.width - 1, b.height - 1);

        g.setColor((selected == rank) ? Color.magenta : Color.black);
        g.drawRect(0, 0, b.width - 1, b.height - 1);

        if (selected == rank) {
          g.drawLine(0, 0, b.width, b.height);
          g.drawLine(0, b.height, b.width, 0);
        }

        if (useLabel) {
          g.setColor(Color.black);
          g.setFont(sf.getFont());
          g.drawString(label[rank], 3, 10);
        }
      }
    } // end inner class ColorInterval


  } // end inner class ColorScale.Panel
}
public void setMinMax ( double min , double max ) { this . min = min ; this . max = max ; interval = ( max - min ) / ( ncolors - 2 ) ; // set edges
 for ( int i = 0 ; i < ncolors ; i ++ ) edge [ i ] = min + i * interval ; lm . sendEvent ( new PropertyChangeEvent ( this , "ColorScaleLimits" , null , this ) ) ; } /**
   * This is an optimization for counting the number of colors in each interval.
   * the histpogram is populated by calls to getIndexFromValue().
   *
   * @return the index with the maximum histogram count.
   */ public int getHistMax ( ) { int max = 0 , maxi = 0 ; for ( int i = 0 ; i <= ncolors ; i ++ ) if ( hist [ i ] > max ) { max = hist [ i ] ; maxi = i ; } return maxi ; } /**
   * reset the histogram.
   */ public void resetHist ( ) { for ( int i = 0 ; i <= ncolors ; i ++ ) hist [ i ] = 0 ; } public String toString ( ) { return name ; } public Object clone ( ) { ColorScale cl = new ColorScale ( name , colors ) ; /*try {
      cl = (ColorScale) super.clone();
    } catch(CloneNotSupportedException e) {
      return null;
    } // ignore

    // non primitive fields must be cloned separately
    cl.name = new String(name);
    cl.set(this);
    cl.construct();  */ return ( Object ) cl ; } /////////// private ////////////////////
 // this is for editing a colorscale
 private void editModeBegin ( ) { Color [ ] editColors = new Color [ ncolors ] ; System . arraycopy ( colors , 0 , editColors , 0 , ncolors ) ; useColors = editColors ; } private void editModeEnd ( boolean accept ) { if ( accept ) { System . arraycopy ( useColors , 0 , colors , 0 , ncolors ) ; } useColors = colors ; } private void setColor ( int i , Color c ) { if ( i >= 0 && i < ncolors ) useColors [ i ] = c ; } /* private void set( ColorScale cs) {
   set(cs.getColors());
 } */ private void setColors ( Color [ ] c ) { ncolors = c . length ; colors = new Color [ ncolors ] ; System . arraycopy ( c , 0 , colors , 0 , ncolors ) ; edge = new double [ ncolors ] ; hist = new int [ ncolors + 1 ] ; useColors = colors ; // ??
 } // serialization
 private void readObject ( ObjectInputStream s ) throws IOException , ClassNotFoundException { s . readInt ( ) ; this . name = s . readUTF ( ) ; this . colors = ( Color [ ] ) s . readObject ( ) ; this . ncolors = colors . length ; constructTransient ( ) ; } private void writeObject ( ObjectOutputStream s ) throws IOException { s . writeInt ( objectVersion ) ; s . writeUTF ( this . name ) ; s . writeObject ( this . colors ) ; } // heres the swing component part of a ColorScale: static so its not part of serialization
 // originally designed to allow popup editor to change colors; this has been disabled; all
 // changes made by COlorManager. design could be cleaned up, but maybe I want that back later?
 public static class Panel extends JPanel { private int type ; private int size = 50 ; private ColorScale cs ; private JLabel unitLabel = new JLabel ( "unit" , SwingConstants . CENTER ) ; private JPanel lpanel ; private boolean editable = false ; private int selected = - 1 ; private int nColorInterval ; private String [ ] label ; private boolean useLabel = true ; private FontUtil . StandardFont sf = FontUtil . getStandardFont ( 10 ) ; public Panel ( Component parent ) { this ( parent , ColorScale . VERTICAL , null ) ; } public Panel ( Component parent , ColorScale cscale ) { this ( parent , ColorScale . VERTICAL , cscale ) ; } public Panel ( Component parent , int type , ColorScale cscale ) { this . cs = ( cscale == null ) ? new ColorScale ( "default" ) : cscale ; this . type = type ; if ( type == ColorScale . VERTICAL ) { setPreferredSize ( new Dimension ( size , 400 ) ) ; setLayout ( new BoxLayout ( this , BoxLayout . Y_AXIS ) ) ; } else { setPreferredSize ( new Dimension ( 400 , size ) ) ; setLayout ( new BoxLayout ( this , BoxLayout . X_AXIS ) ) ; } setListener ( ) ; nColorInterval = cs . getNumColors ( ) ; for ( int i = 0 ; i < nColorInterval ; i ++ ) { ColorInterval intv = new ColorInterval ( nColorInterval - i - 1 ) ; add ( intv ) ; } lpanel = new JPanel ( ) ; lpanel . add ( unitLabel ) ; //unitLabel.setBorder( new javax.swing.border.EtchedBorder());
 if ( type == ColorScale . VERTICAL ) lpanel . setPreferredSize ( new Dimension ( size , 0 ) ) ; else lpanel . setPreferredSize ( new Dimension ( 0 , size ) ) ; add ( lpanel ) ; label = new String [ nColorInterval ] ; calcLabels ( ) ; /* creates a popup men, attaches it to this Panel
     PopupMenu popupMenu = new PopupMenu(this, "options");
     popupMenu.add("Edit", new AbstractAction() {
       public void actionPerformed(ActionEvent e) {
         System.out.println("popup edit action");
         dialog.show();
       }
     }); */ } private void calcLabels ( ) { label [ 0 ] = "<" + Format . d ( cs . getEdge ( 0 ) , sigfig ) ; for ( int i = 1 ; i < nColorInterval - 1 ; i ++ ) { label [ i ] = Format . d ( cs . getEdge ( i ) , sigfig ) ; } label [ nColorInterval - 1 ] = ">" + Format . d ( cs . getEdge ( nColorInterval - 2 ) , sigfig ) ; } private void setListener ( ) { // listen for changes so we can redraw
 cs . addPropertyChangeListener ( new java . beans . PropertyChangeListener ( ) { public void propertyChange ( java . beans . PropertyChangeEvent e ) { if ( e . getPropertyName ( ) . equals ( "ColorScaleLimits" ) ) calcLabels ( ) ; repaint ( ) ; } } ) ; } public ColorScale getColorScale ( ) { return cs ; } // change the current cscale
 public void setColorScale ( ColorScale cscale ) { if ( nColorInterval != cscale . getNumColors ( ) ) { removeAll ( ) ; nColorInterval = cscale . getNumColors ( ) ; label = new String [ nColorInterval ] ; for ( int i = 0 ; i < nColorInterval ; i ++ ) { ColorInterval intv = new ColorInterval ( nColorInterval - i - 1 ) ; add ( intv ) ; label [ i ] = "none" ; } add ( lpanel ) ; revalidate ( ) ; } this . cs = cscale ; setListener ( ) ; calcLabels ( ) ; repaint ( ) ; } // set existing colorscale to have new colors
 public void setColors ( Color [ ] c ) { if ( nColorInterval != c . length ) { removeAll ( ) ; nColorInterval = c . length ; label = new String [ nColorInterval ] ; for ( int i = 0 ; i < nColorInterval ; i ++ ) { ColorInterval intv = new ColorInterval ( nColorInterval - i - 1 ) ; add ( intv ) ; label [ i ] = "none" ; } add ( lpanel ) ; revalidate ( ) ; } cs . setColors ( c ) ; cs . editModeBegin ( ) ; // again
 if ( debugColors ) { for ( int i = 0 ; i < cs . getNumColors ( ) ; i ++ ) System . out . println ( cs . getColor ( i ) ) ; } calcLabels ( ) ; repaint ( ) ; } public void setColor ( Color c ) { cs . setColor ( selected , c ) ; } //public void setEditable( boolean b) { editable = b; }
 public void setEditMode ( boolean on , boolean accept ) { if ( on ) { editable = true ; cs . editModeBegin ( ) ; } else { cs . editModeEnd ( accept ) ; if ( accept ) setColorScale ( cs ) ; selected = - 1 ; editable = false ; } repaint ( ) ; } public void setSelected ( int i ) { selected = i ; } public void setShowText ( boolean b ) { useLabel = b ; } /*private void edit(int which) {
      if (!editable)
        return;
      selected = which;
      repaint();
      cs.setEditMode(true);
      //dialog.show();
    }*/ public void setUnitString ( String s ) { unitLabel . setText ( s ) ; //System.out.println("new text = "+s);
 //unitLabel.repaint(s);
 } public void print ( Graphics2D g , double x , double y , double width , double height ) { int n = cs . getNumColors ( ) ; double size = ( type == ColorScale . VERTICAL ) ? height / n : width / n ; int count = 0 ; for ( int i = 0 ; i < getComponentCount ( ) ; i ++ ) { Component c = getComponent ( i ) ; if ( c instanceof ColorInterval ) { ColorInterval intv = ( ColorInterval ) c ; if ( type == ColorScale . VERTICAL ) intv . printV ( g , ( int ) x , ( int ) ( y + count * size ) , ( int ) width , ( int ) size ) ; else { double xpos = x + width - ( count + 1 ) * size ; intv . printH ( g , ( int ) xpos , ( int ) y , ( int ) size , ( int ) height ) ; } count ++ ; } } } /* private class OkListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.accept();
        repaint();
      }
    }  // end inner class OkListener

    private class CancelListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        selected = -1;
        cs.cancel();
        repaint();
      }
    } // end inner class CancelListener  */ private class ColorInterval extends JComponent { private int rank ; ColorInterval ( int r ) { this . rank = r ; //setPreferredSize( new Dimension(40,40));
 addMouseListener ( new MouseAdapter ( ) { public void mousePressed ( MouseEvent e ) { if ( editable ) { selected = rank ; Panel . this . repaint ( ) ; } } } ) ; } public void printV ( Graphics2D g , int x , int y , int width , int height ) { int textSize = 15 ; // LOOK : neeed to calculate this
 g . setColor ( cs . getColor ( rank ) ) ; g . fillRect ( x , y + textSize , width , height - textSize ) ; //g.setColor( Color.black);
 //g.drawRect( x, y+textSize, width, height-textSize);
 if ( useLabel ) { g . setColor ( Color . black ) ; g . setFont ( sf . getFont ( ) ) ; g . drawString ( label [ rank ] , x + 3 , y + 10 ) ; } } public void printH ( Graphics2D g , int x , int y , int width , int height ) { int textSize = 15 ; // LOOK : neeed to calculate this
 g . setColor ( cs . getColor ( rank ) ) ; g . fillRect ( x , y + textSize , width , height - 2 * textSize ) ; g . setColor ( Color . white ) ; g . drawRect ( x , y + textSize , width , height - 2 * textSize ) ; if ( useLabel ) { g . setColor ( Color . black ) ; g . setFont ( sf . getFont ( ) ) ; if ( rank % 2 == 0 ) // even
 g . drawString ( label [ rank ] , x , y + textSize ) ; else g . drawString ( label [ rank ] , x , y + height ) ; } } public void paintComponent ( Graphics g ) { Rectangle b = getBounds ( ) ; g . setColor ( cs . getColor ( rank ) ) ; g . fillRect ( 0 , 0 , b . width - 1 , b . height - 1 ) ; g . setColor ( ( selected == rank ) ? Color . magenta : Color . black ) ; g . drawRect ( 0 , 0 , b . width - 1 , b . height - 1 ) ; if ( selected == rank ) { g . drawLine ( 0 , 0 , b . width , b . height ) ; g . drawLine ( 0 , b . height , b . width , 0 ) ; } if ( useLabel ) { g . setColor ( Color . black ) ; g . setFont ( sf . getFont ( ) ) ; g . drawString ( label [ rank ] , 3 , 10 ) ; } } } // end inner class ColorInterval
 } // end inner class ColorScale.Panel
 }
Set the data min/max interval. The color intervals are set based on this.
A PropertyChangeEvent is sent when this is called. Currently the intervals are
calculated in the following way (where incr = (max-min)/(n-2)) :
<pre>
<p/>
edge           data interval
0    min             value <= min
1    min+incr        min <= value < min + incr
2    min+2*incr      min+incr <= value < min+2*incr
ith  min+i*incr      min+(i-1)*incr <= value < min+i*incr
n-2  max             min+(n-3)*incr <= value < max
n-1  max             max < value
n                    value = missingDataValue
</pre>

@param min minimum data value
@param max maximum data value
Set the data min / max interval . The color intervals are set based on this . A PropertyChangeEvent is sent when this is called . Currently the intervals are calculated in the following way ( where incr = ( max - min ) / ( n - 2 )) : <pre > <p / > edge data interval 0 min value < = min 1 min + incr min < = value < min + incr 2 min + 2 * incr min + incr < = value < min + 2 * incr ith min + i * incr min + ( i - 1 ) * incr < = value < min + i * incr n - 2 max min + ( n - 3 ) * incr < = value < max n - 1 max max < value n value = missingDataValue < / pre >