package ImageSelector;

import java.awt.*;
import java.lang.*;
import java.util.*;

/**
* TabPanel is a panel which contains another panel (called the client
* panel).  The client panel uses the CardLayout layout manager, allowing
* it to contain one or more panels, one of which is visible at any
* given time.  The TabPanel also displays a picture of a card with
* tabs visible above it.  The TabPanel responds to clicks on these
* tabs by switching the visible contents of the client window to the
* appropriate panel.  Here is some sample code for instancing this
* class and setting it up:
* <pre>
*       TabPanel tp=new TabPanel(;				      
*
*       tp.numRows=1;                           // 1 row of tabs
*
*       tp.addTab("Preferences",prefPanel,0);   // assumes prefPanel was already instanced;
*                                               // adds it to row 0 of tabs                
*
*       tp.addTab("Options",optPanel,0);        // assumes optPanel was already instanced
*                                               // adds it to row 0 of tabs                
*
*       tp.addTab("Status",statPanel,0);        // assumes statPanel was already instanced
*                                               // adds it to row 0 of tabs                
*       tp.notification=new Event(this,MYTYPE,null);
*                                               // set up a notification event
*       tp.toNotify=this;                       // turn on notification
*
*
* </pre>
*/
/*<pre>*/
/**
 * Copyright (c) 1996, Tim DeBruine, Enterprise Integration Technologies,
 * Inc. All rights reserved.<p>
 *
 * RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the 
 * Government is subject to restrictions as set forth in 
 * subparagraph(c)(1)(ii) of the Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 and in similar clauses in the
 * FAR and NASA FAR supplement.<p>
 * 
 * This software is bound by the terms and conditions listed in the
 * attached <a href="../LICENSE">LICENSE file</A>.
 * @author Tim DeBruine
 * @version 1.1
 */

public class TabPanel extends Panel {
/** the client area of the TabPanel */
        public Panel client;

/* vector to hold names of tabs (which are the same as the
* names of the panels in the client area) */
        Vector tabs;

/* vector to hold row assignment for each tab */
        Vector rows;

/* vector to remember order in which rows were drawn during last paint */
        Vector drawnRows;

/* vector to remember amount of padding required in each row */
        Vector paddings;

/* vector to remember number of tabs in each row */
        Vector nums;

/* index of currently selected tab */
        public int sel;

/* width of client area */
        int clientwidth;

/* height of client area */
        int clientheight;

/** height of tab; default=20 */
        public int tabsheight=20;

/** amount of space between tab text and bottom egde of tab; default=5 */
        public int tabsundertext=5;

/** amount of space between tab text and left edge of tab; default=6 */
        public int tabsleftinset=6;

/** amount of extra space to add to each tab by default in addition
* to the tab's text (note that additional padding may be added when
* drawn); default=12 */
        public int tabsextrawidth=12;

/** amount by which left, top, and right edges each grow when a tab is
* selected; default=2 */
        public int tabshighlightedgrow=2;

/** amount of inset from card edge given to client, on left and right edges
* of client; default=10 */
        public int clientinseth=10;

/** amount of inset from card edge given to client, on top and bottom edges
* of client; default=10 */
        public int clientinsetv=10;

/** amount of inset from TabPanel edge given to card on left side; default=0 */
        public int cardinsetleft=0;

/** amount of inset from TabPanel edge given to card on right side; default=0 */
        public int cardinsetright=0;

/** amount of inset from TabPanel edge given to card on bottom; default=0 */
        public int cardinsetbottom=0;

/* client area x coordinate within TabPanel */
        int clientx;

/* client area y coordinate within TabPanel */
        int clienty;

/* card area x coordinate within TabPanel */
        int cardleft;

/* card area width */
        int cardwidth;

/* card area height */
        int cardheight;

/* card area y coordinate within TabPanel */
        int cardtop;

/* y coordinate of bottom of tabs area */
        int tabsbottom;

/** number of rows in tabs area */
        public int numRows;

/** this Component will be notified when the user selects a different panel;
* if it is null, no notification occurs; default=null */
        public Component toNotify = null;

/** this is the event that will be sent as a notification when the
* user selects a different panel */
        public Event notification;

/** constructor -- caller specifies initial width and height of client area */
        public TabPanel() {
                // specify "no layout manager"
                setLayout(null);

                // instance the list of tabs
                tabs=new Vector();
                rows=new Vector();

                // initial card selection to 0
                sel=0;

                // initialize number of rows to 0
                numRows=0;

                //set up the client window area
                client=new Panel();
                client.setLayout(new CardLayout());
                add(client);

	}

        void setup(int w,int h) {
                // figure out how big to make client area to
                // comply with resize request
                clientwidth=w-cardinsetleft-cardinsetright
                        -clientinsetv-clientinsetv;

                // set up the drawing numbers
                tabsbottom=numRows*tabsheight+tabshighlightedgrow;
                cardleft=cardinsetleft;
                clientx=cardleft+clientinseth;
                clienty=tabsbottom+clientinsetv;
                clientheight=h-tabsbottom-clientinsetv
                        -clientinsetv-cardinsetbottom;
                cardtop=tabsbottom;
                cardwidth=w-cardinsetleft-cardinsetright-1;
                cardheight=h-cardinsetbottom-tabsbottom-1;                
                client.move(clientx,clienty);
                client.resize(clientwidth,clientheight);
        }

/**
 * intercepts reshape calls to resize client first
 * @param x X coordinate.
 * @param y Y coordinate.
 * @param w Width.
 * @param h Height.
 */
        public void reshape(int x,int y,int w,int h) {
                setup(w,h);             // resize client        
                super.reshape(x,y,w,h);
        }

/** this method is used instead of the "add" method usually employed when
* adding components to a conatiner; caller passes name of panel being added,
* the panel being added, and the row of tabs to which the tab should be
* added (numbering of tab rows begins with 0)
* @param s name of component and name on tab
* @param p the panel to show for this tab
* @param r the row of tabs on which to show this tab
*/
        public void addTab(String s,Panel p,int r) {
                tabs.addElement(s);
                rows.addElement(new Integer(r));
                client.add(s,p);
        }

/* this method is used internally to handle mouse click events */
        void deal(Event evt) {
                int row;
                int i;
                int topy;
                int x,x_right;
                int x_in_panel,y_in_panel;
                int pad,num;
                FontMetrics fm;

                // get font metrics
                fm=getFontMetrics(getFont());

                // bail if row is not withing tabs
                y_in_panel=evt.y;
                x_in_panel=evt.x;
                
                topy=tabsbottom-numRows*tabsheight;
                if (y_in_panel>=tabsbottom || y_in_panel<topy) return;

                // find row in which selection occurred
                i=(y_in_panel-topy)/tabsheight;
                row=((Integer)drawnRows.elementAt(i)).intValue();
                pad=((Integer)paddings.elementAt(i)).intValue();
                num=((Integer)nums.elementAt(i)).intValue();

                // now iterate throught tabs trying to find a
                // tab whose x-extent includes this event's x
                x=cardleft+tabshighlightedgrow;

                for (i=0; i<tabs.size(); i++) {
                        if (((Integer)rows.elementAt(i)).intValue()==row) {
                                String s=(String)tabs.elementAt(i);
                                int padamt=0;

                                if (pad>0) {
                                        padamt=(pad/num);
                                        pad-=padamt;
                                }
                                num--;

                                x_right=x+tabsextrawidth+fm.stringWidth(s)+padamt;

                                if (x_in_panel>=x && x_in_panel<x_right) {
                                        ((CardLayout)client.getLayout()).show(client,s);

                                        // notify
                                        if (toNotify!=null) {
                                                notification.arg=client.getComponent(i);
                                                toNotify.postEvent(notification);
                                        }

                                        sel=i;
                                        repaint();
                                        break;
                                }

                                x=x_right;
                        }
                }
        }
/* this method handles mouse click events */
        public boolean handleEvent(Event evt) {
                if ((evt.target==this) && (evt.id==Event.MOUSE_DOWN)) {
                        deal(evt);
                }
                return super.handleEvent(evt);
        }

/* this method uses absolute positioning (no LayoutManager) to draw
* the tabs and card background on which the client panel is placed */        
        public void paint(Graphics g) {
                Integer row_of_selection;
                int x,y;
                int selectionx=0;
                int selectionpad=0;
                int selectionpadleft=0;
                int i;
                int j;
                int countwidth=0;
                int countelems=0;
                int k;

                FontMetrics fm;
                paddings=new Vector();
                nums=new Vector();

                // prepare a vector to hold the rows as they are drawn
                drawnRows=new Vector();

                // get font metrics -- these will be needed for drawing tabs
                fm=getFontMetrics(getFont());

                // figure out which row selection is in
                row_of_selection=(Integer)rows.elementAt(sel);

                // make a pass through all the rows in the order in
                // which they will be draw, adding up widths and
                // numbers of elements

                for (i=0; i<numRows; i++) {
                        if (i!=row_of_selection.intValue()) {
                                countwidth=0;
                                countelems=0;
                                for (j=0; j<rows.size(); j++) {
                                        if (((Integer)rows.elementAt(j)).intValue()==i) {
                                                String s;

                                                s=(String)tabs.elementAt(j);
                                                countelems++;
                                                countwidth+=fm.stringWidth(s);
                                                countwidth+=tabsextrawidth;
                                        }
                                }

                                // now add elements to vectors
                                int temp=cardwidth-tabshighlightedgrow
                                        -tabshighlightedgrow-countwidth;

                                paddings.addElement(new Integer(temp));
                                nums.addElement(new Integer(countelems));
                        }
                }

                countwidth=0;
                countelems=0;

                for (j=0; j<rows.size(); j++) {
                        if (((Integer)rows.elementAt(j)).intValue()==row_of_selection.intValue()) {
                                String s;

                                s=(String)tabs.elementAt(j);
                                countelems++;
                                countwidth+=fm.stringWidth(s);
                                countwidth+=tabsextrawidth;
                        }
                }
                // now add elements to vectors
                int temp=cardwidth-tabshighlightedgrow
                        -tabshighlightedgrow-countwidth;

                paddings.addElement(new Integer(temp));
                nums.addElement(new Integer(countelems));

                // now draw, using information from first pass to do
                // padding
                // draw other rows first
                y=tabsbottom-tabsheight*(numRows-1);        // starting y
                k=0;

                for (i=0; i<numRows; i++) {
                        x=cardleft+tabshighlightedgrow;         // starting x
                        if (i!=row_of_selection.intValue()) {
                                drawnRows.addElement(new Integer(i));
                                int padAmt=((Integer)paddings.elementAt(k)).intValue();
                                int num=((Integer)nums.elementAt(k)).intValue();
                                for (j=0; j<rows.size(); j++) {
                                        if (((Integer)rows.elementAt(j)).intValue()==i) {
                                                String s;
                                                int fieldwidth;
                                                int pad,padLeft;

                                                // figure out how much to pad this selection by
                                                pad=0;
                                                padLeft=0;
                                                if (padAmt>0) {
                                                        pad=padAmt/num;
                                                        padLeft=pad/2;
                                                        padAmt-=pad;
                                                }
                                                num--;                                                

                                                s=(String)tabs.elementAt(j);
                                                fieldwidth=fm.stringWidth(s);
        
                                                g.setColor(Color.lightGray);
//                                                g.fill3DRect(x,y-tabsheight,
//                                                        fieldwidth+tabsextrawidth+pad,tabsheight,true);

                                                drawTab(g,x,y-tabsheight,
                                                        fieldwidth+tabsextrawidth+pad-1,tabsheight-1);


                                                g.setColor(Color.black);
                                                g.drawString(s,x+tabsleftinset+padLeft,y-tabsundertext);
                                                x+=tabsextrawidth+fieldwidth+pad;
                                        }
                                }

                                y+=tabsheight;
                                k++;
                        }
                }

                // draw row of selection without drawing selection
                drawnRows.addElement(new Integer(row_of_selection.intValue()));

                x=cardleft+tabshighlightedgrow;         // starting x
                int padAmt=((Integer)paddings.elementAt(k)).intValue();
                int num=((Integer)nums.elementAt(k)).intValue();

                int foundfirst=0;

                for (j=0; j<rows.size(); j++) {
                        if (((Integer)rows.elementAt(j)).intValue()==row_of_selection.intValue()) {
                                String s;
                                int fieldwidth;
                                int pad,padLeft;

                                // figure out how much to pad this selection by
                                pad=0;
                                padLeft=0;
                                if (padAmt>0) {
                                        pad=padAmt/num;
                                        padLeft=pad/2;
                                        padAmt-=pad;                                                        
                                }
                                num--;                                                

                                s=(String)tabs.elementAt(j);
                                fieldwidth=fm.stringWidth(s);

                                if (j!=sel) {
                                        if (foundfirst==0) foundfirst=2;

                                        g.setColor(Color.lightGray);
//                                        g.fill3DRect(x,y-tabsheight,
//                                                fieldwidth+tabsextrawidth+pad,tabsheight,true);

                                        drawTab(g,x,y-tabsheight,
                                                fieldwidth+tabsextrawidth+pad-1,tabsheight-1);


                                        g.setColor(Color.black);
                                        g.drawString(s,x+tabsleftinset+padLeft,y-tabsundertext);
                                }
                                else {
                                        if (foundfirst==0) foundfirst=1;

                                        selectionx=x;
                                        selectionpadleft=padLeft;
                                        selectionpad=pad;
                                }
                                x+=tabsextrawidth+fieldwidth+pad;

                        }
                }

                // finally!  draw selection
                String s;
                int fieldwidth;

                s=(String)tabs.elementAt(sel);
                fieldwidth=fm.stringWidth(s);

                g.setColor(Color.lightGray);
                drawTab(g,selectionx-tabshighlightedgrow,y-tabsheight-tabshighlightedgrow,
                        fieldwidth+tabsextrawidth+tabshighlightedgrow+
                        tabshighlightedgrow+selectionpad,tabsheight+tabshighlightedgrow+1);



                g.setColor(Color.black);
                g.drawString(s,selectionx+tabsleftinset+selectionpadleft,y-tabsundertext-1);


                // draw the box for the card
                g.setColor(Color.lightGray);
                drawBox(g,cardleft,cardtop,cardwidth,cardheight);

                // now draw a cleverly placed rectangle to blot out the
                // line between the selected tab and the card
                g.fillRect(selectionx-tabshighlightedgrow+2,y-2,fieldwidth+
                        tabsextrawidth+tabshighlightedgrow+tabshighlightedgrow+
                        selectionpad-3,5);

                g.setColor(Color.gray);
                g.drawLine(
                        selectionx+fieldwidth+tabsextrawidth+tabshighlightedgrow+
                        tabshighlightedgrow+selectionpad-3,
                        y,
                        selectionx+fieldwidth+tabsextrawidth+tabshighlightedgrow+
                        tabshighlightedgrow+selectionpad-3,
                        y);

                if (foundfirst==2) {
                        g.setColor(Color.lightGray);
                        g.drawLine(selectionx-1,y+1,selectionx+1,y+1);
                }

                g.setColor(Color.black);
                g.drawLine(
                        selectionx+fieldwidth+tabsextrawidth+tabshighlightedgrow+
                        tabshighlightedgrow+selectionpad-2,
                        y,
                        selectionx+fieldwidth+tabsextrawidth+tabshighlightedgrow+
                        tabshighlightedgrow+selectionpad-2,
                        y);
                                        
        }

        void drawBox(Graphics g,int x,int y,int width,int height) {
                g.setColor(Color.white);
                g.drawLine(x,y,x+width-1,y);
                g.drawLine(x,y+1,x+width-2,y+1);
                g.drawLine(x,y+2,x,y+height-1);
                g.drawLine(x+1,y+2,x+1,y+height-2);

                g.setColor(Color.gray);
                g.drawLine(x+width-1,y+1,x+width-1,y+height-1);
                g.drawLine(x+1,y+height-1,x+width-2,y+height-1);

                g.setColor(Color.black);
                g.drawLine(x+width,y,x+width,y+height);
                g.drawLine(x,y+height,x+width-1,y+height);

                g.setColor(Color.lightGray);
                g.fillRect(x+2,y+2,width-3,height-3);
                
        }

        void drawTab(Graphics g,int x,int y,int width,int height) {
                g.setColor(Color.white);
                g.drawLine(x+2,y,x+width-2,y);
                g.drawLine(x+1,y+1,x+width-2,y+1);
                g.drawLine(x,y+2,x,y+height);
                g.drawLine(x+1,y+1,x+1,y+height);

                g.setColor(Color.gray);
                g.drawLine(x+width-1,y+2,x+width-1,y+height);

                g.setColor(Color.black);
                g.drawLine(x+width-1,y+1,x+width-1,y+1);
                g.drawLine(x+width,y+2,x+width,y+height);

                g.setColor(Color.lightGray);
                g.fillRect(x+2,y+2,width-3,height-1);

        }

}

