Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.     Sketch Elements: Chemistry molecular diagram drawing tool.
  3.    
  4.     (c) 2008 Dr. Alex M. Clark
  5.    
  6.     Released as GNUware, under the Gnu Public License (GPL)
  7.    
  8.     See www.gnu.org for details.
  9. */
  10.  
  11. package WIMSchem;
  12.  
  13. import java.io.*;
  14. import java.awt.*;
  15. import java.util.*;
  16. import java.awt.image.*;
  17. import java.awt.event.*;
  18. import javax.swing.*;
  19.  
  20. /*
  21.     JLineup: a medium-weight layout-support component for Swing, which encapsulates some of the fundamental aspects of making
  22.     everything in a panel line up nicely. Somewhat of a subset of the functionality offered by GroupLayout (v1.6 and later).
  23.    
  24.     Two modes:
  25.         VERTICAL - the child components are lined up from top to bottom; titles+padding line up
  26.         HORIZONTAL - the child components are lined up from left to right; titles only line up on the baseline
  27.        
  28.     Both modes have optional titles, though the vertical invocation goes further than just the basic convenience of not
  29.     needing to do the widget creation. Both have stretch weights for X & Y, though the meanings are inverted. For vertical
  30.     lineups, the Y weights affect the overall size of the widget, while the X weights just affect how existing space is
  31.     filled. The converse is true for horizontal lineups.
  32. */
  33.  
  34.  
  35. public class JLineup extends JPanel
  36. {
  37.     class Unit
  38.     {
  39.         Component c;
  40.         JLabel label;
  41.         int stretchX,stretchY;
  42.     }
  43.     private ArrayList<Unit> content=new ArrayList<Unit>();
  44.  
  45.     public static final int VERTICAL=1;
  46.     public static final int HORIZONTAL=2;
  47.     private int dir,padding;
  48.  
  49.     // Constructor:
  50.     // dir: must be VERTICAL or HORIZONTAL
  51.     // padding: number of pixels between each component, and around the edges
  52.  
  53.     public JLineup(int dir)
  54.     {
  55.         super();
  56.         this.dir=dir;
  57.         this.padding=0;
  58.     }
  59.     public JLineup(int dir,int padding)
  60.     {
  61.         super();
  62.         this.dir=dir;
  63.         this.padding=padding;
  64.     }
  65.    
  66.     // for cleaning house
  67.    
  68.     public void clear()
  69.     {
  70.         for (int n=0;n<content.size();n++)
  71.         {
  72.             Unit u=content.get(n);
  73.             super.remove(u.c);
  74.             if (u.label!=null) super.remove(u.label);
  75.         }
  76.         content.clear();
  77.     }
  78.     public void remove(Component c)
  79.     {
  80.         for (int n=0;n<content.size();n++)
  81.         {
  82.             Unit u=content.get(n);
  83.             if (u.c==c)
  84.             {
  85.                 super.remove(c);
  86.                 if (u.label!=null) super.remove(u.label);
  87.             }
  88.         }
  89.     }
  90.    
  91.     // convenience shortcuts
  92.    
  93.     public Component add(Component c) {return add(c,null,0,0);}
  94.     public Component add(Component c,String title) {return add(c,title,0,0);}
  95.    
  96.     public Component add(Component c,String title,int stretchX,int stretchY)
  97.     {
  98.         super.add(c);
  99.  
  100.         Unit u=new Unit();
  101.         u.c=c;
  102.         u.label=null;
  103.         u.stretchX=stretchX;
  104.         u.stretchY=stretchY;
  105.        
  106.         if (title!=null)
  107.         {
  108.             u.label=new JLabel(title);
  109.             super.add(u.label);
  110.         }
  111.        
  112.         content.add(u);
  113.         invalidate();
  114.        
  115.         return c;
  116.     }
  117.    
  118.     public Dimension getMinimumSize()
  119.     {
  120.         Dimension sz=new Dimension(0,0);
  121.        
  122.         if (dir==VERTICAL)
  123.         {
  124.             int mw=0;
  125.             for (int n=0;n<content.size();n++)
  126.             {
  127.                 Unit u=content.get(n);
  128.                 mw=Math.max(mw,u.c.getPreferredSize().width);
  129.                 sz.height+=Math.max(u.label==null ? 0 : u.label.getPreferredSize().height,u.c.getPreferredSize().height);
  130.             }
  131.             sz.width=calculateTitleWidth()+mw+2*padding;
  132.             sz.height+=padding*(content.size()+1);
  133.         }
  134.         else // HORIZONTAL
  135.         {
  136.             int mh=0;
  137.             for (int n=0;n<content.size();n++)
  138.             {
  139.                 Unit u=content.get(n);
  140.                 if (u.label!=null)
  141.                 {
  142.                     sz.width+=u.label.getPreferredSize().width+padding;
  143.                     sz.height=Math.max(sz.height,u.label.getPreferredSize().height);
  144.                 }
  145.                 sz.width+=u.c.getPreferredSize().width;
  146.                 sz.height=Math.max(sz.height,u.c.getPreferredSize().height);
  147.             }
  148.             sz.width+=padding*(content.size()+1);
  149.             sz.height+=padding*2;
  150.         }
  151.        
  152.         return sz;
  153.     }
  154.     public Dimension getPreferredSize() {return getMinimumSize();}
  155.     public Dimension getMaximumSize()
  156.     {
  157.         Dimension sz=new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE);
  158.         boolean anyX=false,anyY=false;
  159.         for (int n=0,y=0;n<content.size();n++)
  160.         {
  161.             Unit u=content.get(n);
  162.             anyX=anyX || u.stretchX>0;
  163.             anyY=anyY || u.stretchY>0;
  164.         }
  165.         if (!anyX || !anyY)
  166.         {
  167.             Dimension psz=getPreferredSize();
  168.             if (!anyX) sz.width=psz.width;
  169.             if (!anyY) sz.height=psz.height;
  170.         }
  171.  
  172.         return sz;
  173.     }
  174.    
  175.     public void doLayout()
  176.     {
  177.         if (dir==VERTICAL) layoutVertical();
  178.         else layoutHorizontal();
  179.     }
  180.    
  181.     private void layoutVertical()
  182.     {
  183.         Dimension prefsz=getPreferredSize(),cursz=getSize();
  184.         int totalStretch=0,stretchPoints=cursz.height-prefsz.height;
  185.         if (stretchPoints>0) for (int n=0;n<content.size();n++) totalStretch+=content.get(n).stretchY;
  186.        
  187.         int tw=calculateTitleWidth(),residual=stretchPoints,cw=cursz.width-tw-2*padding;
  188.         for (int n=0,y=padding;n<content.size();n++)
  189.         {
  190.             Unit u=content.get(n);
  191.             int h=Math.max(u.label==null ? 0 : u.label.getPreferredSize().height,u.c.getPreferredSize().height);
  192.             if (u.stretchY>0 && stretchPoints>0)
  193.             {
  194.                 int extra=(int)Math.min(Math.ceil(stretchPoints*u.stretchY/(double)totalStretch),residual);
  195.                 h+=extra;
  196.                 residual-=extra;
  197.             }
  198.             if (u.label!=null)
  199.             {
  200.                 int ly=y;
  201.                 if (u.c instanceof JComponent)
  202.                 {
  203.                     int delta=((JComponent)u.c).getBaseline(tw,h)-u.label.getBaseline(cw,u.label.getPreferredSize().height);
  204.                     ly+=delta>0 ? delta : 0;
  205.                 }
  206.                 u.label.setBounds(padding,ly,tw,u.label.getPreferredSize().height);
  207.             }
  208.             u.c.setBounds(padding+tw,y,u.stretchX==0 ? u.c.getPreferredSize().width : cw,h);
  209.            
  210.             y+=h+padding;
  211.         }
  212.     }
  213.    
  214.     private void layoutHorizontal()
  215.     {
  216.         Dimension prefsz=getPreferredSize(),cursz=getSize();
  217.         int totalStretch=0,stretchPoints=cursz.height-prefsz.height-2*padding;
  218.         if (stretchPoints>0) for (int n=0;n<content.size();n++) totalStretch+=content.get(n).stretchX;
  219.        
  220.         int residual=stretchPoints;
  221.         for (int n=0,x=padding;n<content.size();n++)
  222.         {
  223.             Unit u=content.get(n);
  224.             int w=u.c.getPreferredSize().width,h=cursz.height-2*padding;
  225.             int ch=u.stretchY==0 ? u.c.getPreferredSize().height : h;
  226.             if (u.stretchX>0 && stretchPoints>0)
  227.             {
  228.                 int extra=(int)Math.min(Math.ceil(stretchPoints*u.stretchX/(double)totalStretch),residual);
  229.                 w+=extra;
  230.                 residual-=extra;
  231.             }
  232.             if (u.label!=null)
  233.             {
  234.                 int ly=padding;
  235.                 Dimension lsz=u.label.getPreferredSize();
  236.                 if (u.c instanceof JComponent)
  237.                 {
  238.                     // (NOTE: this matches the baseline for pairs; probably should do for all components...)
  239.                     int delta=((JComponent)u.c).getBaseline(w,ch)-u.label.getBaseline(lsz.width,lsz.height);
  240.                     ly+=delta>0 ? delta : 0;
  241.                 }
  242.                 u.label.setBounds(x,ly,lsz.width,lsz.height);
  243.                 x+=lsz.width+padding;
  244.             }
  245.             u.c.setBounds(x,padding,w,ch);
  246.             x+=w+padding;
  247.         }
  248.     }
  249.    
  250.     private int calculateTitleWidth()
  251.     {
  252.         int w=0;
  253.         for (int n=0;n<content.size();n++)
  254.         {
  255.             Unit u=content.get(n);
  256.             if (u.label==null) continue;
  257.             w=Math.max(w,u.label.getPreferredSize().width);
  258.         }
  259.         if (w>0) w+=padding;
  260.         return w;
  261.     }
  262. }
  263.