PageRenderTime 143ms CodeModel.GetById 130ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/CommonControls/ise/java/awt/LambdaLayout.java

#
Java | 315 lines | 171 code | 18 blank | 126 comment | 34 complexity | 11c0c46e6c41c2b43ddb70829ee03611 MD5 | raw file
  1
  2package ise.java.awt;
  3
  4import java.awt.LayoutManager2;
  5import java.awt.Component;
  6import java.awt.Container;
  7import java.awt.Dimension;
  8import java.awt.Insets;
  9import java.awt.Point;
 10import java.io.Serializable;
 11
 12/**
 13 * LambdaLayout, a Java layout manager.<br>
 14 * Copyright (C) 2001, Dale Anson<br>
 15 *<br>
 16 * This library is free software; you can redistribute it and/or<br>
 17 * modify it under the terms of the GNU Lesser General Public<br>
 18 * License as published by the Free Software Foundation; either<br>
 19 * version 2.1 of the License, or (at your option) any later version.<br>
 20 *<br>
 21 * This library is distributed in the hope that it will be useful,<br>
 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
 24 * Lesser General Public License for more details.<br>
 25 *<br>
 26 * You should have received a copy of the GNU Lesser General Public<br>
 27 * License along with this library; if not, write to the Free Software<br>
 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA<br>
 29 * <p>
 30 * LambdaLayout -- based on KappaLayout, but handles stretching of components
 31 * differently. From e-mail I've received about KappaLayout, many people are
 32 * expecting a different stretching behavior when resizing a Frame. LambdaLayout
 33 * has this expected behaviour, in that components with the 's' constraint set to
 34 * 'w', 'h', or 'wh'/'hw' will resize as the frame resizes.  Like KappaLayout,
 35 * LambdaLayout respects the preferred size of components and will not shrink
 36 * a component to less than it's preferred size.<br>
 37 * Example use:<br>
 38 * This will put a button on a panel in the top of its cell, stretched to
 39 * fill the cell width, with a 3 pixel pad:<br>
 40 * <code>
 41 * Panel p = new Panel(new LambdaLayout());
 42 * Button b = new Button("OK");
 43 * p.add(b, "0, 0, 1, 2, 2, w, 3");
 44 * </code>
 45 * <br>
 46 * The constraints string has this layout:<br>
 47 * "x, y, w, h, a, s, p"<br>
 48 * defined as follows:<br>
 49 * <ul>
 50 * <li>'x' is the column to put the component, default is 0<br>
 51 * <li>'y' is the row to put the component, default is 0<br>
 52 * <li>'w' is the width of the component in columns (column span), default is 1.
 53 * Can also be R or r, which means the component will span the remaining cells
 54 * in the row.<br>
 55 * <li>'h' is the height of the component in rows (row span), default is 1.
 56 * Can also be R or r, which means the component will span the remaining cells
 57 * in the column.<br>
 58 * <li>'a' is the alignment within the cell. 'a' can be a value between 0 and 8,
 59 * inclusive, (default is 0) and causes the alignment of the component within the cell to follow
 60 * this pattern:<br>
 61 * 8 1 2<br>
 62 * 7 0 3<br>
 63 * 6 5 4<br>, or<br>
 64 * 0 horizontal center, vertical center,<br>
 65 * 1 horizontal center, vertical top,<br>
 66 * 2 horizontal right, vertical top,<br>
 67 * 3 horizontal right, vertical center,<br>
 68 * 4 horizontal right, vertical bottom,<br>
 69 * 5 horizontal center, vertical bottom,<br>
 70 * 6 horizontal left, vertical bottom,<br>
 71 * 7 horizontal left, vertical center,<br>
 72 * 8 horizontal left, vertical top.<br>
 73 * <p>
 74 * By popular request, the alignment constraint can also be represented as:<br>
 75 * NW N NE<br>
 76 * &nbsp;W 0 E<br>
 77 * SW S SE<br>
 78 * which are compass directions for alignment within the cell.
 79 * <li>'s' is the stretch value. 's' can have these values:<br>
 80 * 'w' stretch to fill cell width<br>
 81 * 'h' stretch to fill cell height<br>
 82 * 'wh' or 'hw' stretch to fill both cell width and cell height<br>
 83 * '0' (character 'zero') no stretch (default)
 84 * <li>'p' is the amount of padding to put around the component. This much blank
 85 * space will be applied on all sides of the component, default is 0.
 86 * </ul>
 87 * Parameters may be omitted (default  values will be used), e.g.,
 88 * <code> p.add(new Button("OK), "1,4,,,w,");</code><br>
 89 * which means put the button at column 1, row 4, default 1 column wide, default
 90 * 1 row tall, stretch to fit width of column, no padding. <br>
 91 * Spaces in the parameter string are ignored, so these are identical:<br>
 92 * <code> p.add(new Button("OK), "1,4,,,w,");</code><br>
 93 * <code> p.add(new Button("OK), " 1, 4,   , , w");</code><p>
 94 * Rather than use a constraints string, a Constraints object may be used
 95 * directly, similar to how GridBag uses a GridBagConstraint. E.g,<br>
 96 * <code>
 97 * Panel p = new Panel();<br>
 98 * LambdaLayout tl = new LambdaLayout();<br>
 99 * p.setLayout(tl);<br>
100 * LambdaLayout.Constraints con = tl.getConstraint();<br>
101 * con.x = 1;<br>
102 * con.y = 2;<br>
103 * con.w = 2;<br>
104 * con.h = 2;<br>
105 * con.s = "wh";<br>
106 * panel.add(new Button("OK"), con);<br>
107 * con.x = 3;<br>
108 * panel.add(new Button("Cancel"), con);<br>
109 * </code><br>
110 * Note that the same Constraints can be reused, thereby reducing the number of
111 * objects created.<p>
112 * @author Dale Anson
113 */
114
115public class LambdaLayout extends KappaLayout implements LayoutManager2, Serializable {
116
117   /**
118    * Required by LayoutManager, does all the real layout work. This is the only
119    * method in LambdaLayout, all other methods are in KappaLayout.
120    */
121   public void layoutContainer(Container parent) {
122      synchronized(parent.getTreeLock()) {
123         Insets insets = parent.getInsets();
124         int max_width = parent.getSize().width - (insets.left + insets.right);
125         int max_height = parent.getSize().height - (insets.top + insets.bottom);
126         int x = insets.left;    // x and y location to put component in pixels
127         int y = insets.top;
128         int xfill = 0;          // how much extra space to put between components
129         int yfill = 0;          // when stretching to fill entire container
130
131         // make sure preferred size is known, a side effect is that countColumns
132         // and countRows are automatically called.
133         calculateDimensions();
134
135         // if necessary, calculate the amount of padding to add between the
136         // components to fill the container
137         if ( max_width > _preferred_width ) {
138            int pad_divisions = 0;
139            for ( int i = 0; i < _col_count; i++ ) {
140               if ( _col_widths[i] >= 0 )
141                  ++pad_divisions;
142            }
143            if ( pad_divisions > 0 )
144               xfill = (max_width - _preferred_width) / pad_divisions / 2;
145         }
146         if ( max_height > _preferred_height ) {
147            int pad_divisions = 0;
148            for ( int i = 0; i < _row_count; i++ ) {
149               if ( _row_heights[i] >= 0 )
150                  ++pad_divisions;
151            }
152            if ( pad_divisions > 0 )
153               yfill = (max_height - _preferred_height) / pad_divisions / 2;
154         }
155
156         // do the layout. Components are handled by columns, top to bottom,
157         // left to right. 
158         Point cell = new Point();
159         for ( int current_col = 0; current_col < _col_count; current_col++ ) {
160            // adjust x for previous column widths
161            x = insets.left;
162            for ( int n = 0; n < current_col; n++ ) {
163               x += Math.abs(_col_widths[n]);
164               if ( _col_widths[n] > 0 )
165                  x += xfill * 2;
166            }
167
168            for ( int current_row = 0; current_row < _row_count; current_row++ ) {
169               // adjust y for previous row heights
170               y = insets.top;
171               for ( int n = 0; n < current_row; n++ ) {
172                  y += Math.abs(_row_heights[n]);
173                  if ( _row_heights[n] > 0 ) {
174                     y += yfill * 2;
175                  }
176               }
177
178               cell.x = current_col;
179               cell.y = current_row;
180               Component c = (Component)_components.get(cell);
181               if ( c != null && c.isVisible() ) {
182                  Dimension d = c.getPreferredSize();
183                  Constraints q = (Constraints)_constraints.get(c);
184
185                  // calculate width of spanned columns = sum(preferred column
186                  // widths) + sum(xfill between columns)
187                  int sum_cols = 0;
188                  int sum_xfill = xfill * 2;
189                  for ( int n = current_col; n < current_col + q.w; n++ ) {
190                     sum_cols += Math.abs(_col_widths[n]);
191                  }
192                  if ( _col_widths[current_col] > 0 ) {
193                     for ( int n = current_col; n < current_col + q.w - 1; n++ ) {
194                        if ( _col_widths[n] > 0 )
195                           sum_xfill += xfill * 2;
196                     }
197                     sum_cols += sum_xfill;
198                  }
199
200                  // calculate height of spanned rows
201                  int sum_rows = 0;
202                  int sum_yfill = yfill * 2;
203                  for ( int n = current_row; n < current_row + q.h; n++ ) {
204                     sum_rows += Math.abs(_row_heights[n]);
205                  }
206                  if ( _row_heights[current_row] > 0 ) {
207                     for ( int n = current_row; n < current_row + q.h - 1; n++ ) {
208                        if ( _row_heights[n] > 0 )
209                           sum_yfill += yfill * 2;
210                     }
211                     sum_rows += sum_yfill;
212                  }
213
214                  int x_adj;
215                  int y_adj;
216
217                  // stretch if required
218                  if ( q.s.indexOf("w") != -1 && _col_widths[current_col] > 0 ) {
219                     d.width = sum_cols - q.p * 2;
220                     x_adj = q.p * 2;
221                  }
222                  else {
223                     x_adj = sum_cols - d.width;
224                  }
225
226                  if ( q.s.indexOf("h") != -1 && _row_heights[current_row] > 0 ) {
227                     d.height = sum_rows - q.p * 2;
228                     y_adj = q.p * 2;
229                  }
230                  else {
231                     y_adj = sum_rows - d.height;
232                  }
233
234                  // in each case, add the adjustment for the cell, then subtract
235                  // the correction after applying it.  This prevents the corrections
236                  // from improperly accumulating across cells. Padding must be handled
237                  // explicitly for each case.
238                  // Alignment follows this pattern within the spanned cells:
239                  // 8 1 2   or   NW N NE
240                  // 7 0 3         W 0 E
241                  // 6 5 4        SW S SE
242                  switch ( q.a ) {
243                     case N:     // top center
244                        x += x_adj / 2 ;
245                        y += q.p;
246                        c.setBounds(x, y, d.width, d.height);
247                        x -= x_adj / 2;
248                        y -= q.p;
249                        break;
250                     case NE:    // top right
251                        x += x_adj - q.p;
252                        y += q.p;
253                        c.setBounds(x, y, d.width, d.height);
254                        x -= x_adj - q.p;
255                        y -= q.p;
256                        break;
257                     case E:     // center right
258                        x += x_adj - q.p;
259                        y += y_adj / 2;
260                        c.setBounds(x, y, d.width, d.height);
261                        x -= x_adj - q.p;
262                        y -= y_adj / 2;
263                        break;
264                     case SE:    // bottom right
265                        x += x_adj - q.p;
266                        y += y_adj - q.p;
267                        c.setBounds(x, y, d.width, d.height);
268                        x -= x_adj - q.p;
269                        y -= y_adj - q.p;
270                        break;
271                     case S:     // bottom center
272                        x += x_adj / 2;
273                        y += y_adj - q.p;
274                        c.setBounds(x, y, d.width, d.height);
275                        x -= x_adj / 2;
276                        y -= y_adj - q.p;
277                        break;
278                     case SW:    // bottom left
279                        x += q.p;
280                        y += y_adj - q.p;
281                        c.setBounds(x, y, d.width, d.height);
282                        x -= q.p;
283                        y -= y_adj - q.p;
284                        break;
285                     case W:     // center left
286                        x += q.p;
287                        y += y_adj / 2;
288                        c.setBounds(x, y, d.width, d.height);
289                        x -= q.p;
290                        y -= y_adj / 2;
291                        break;
292                     case NW:    // top left
293                        x += q.p;
294                        y += q.p;
295                        c.setBounds(x, y, d.width, d.height);
296                        x -= q.p;
297                        y -= q.p;
298                        break;
299                     case 0:     // dead center
300                     default:
301                        x += x_adj / 2;
302                        y += y_adj / 2;
303                        c.setBounds(x, y, d.width, d.height);
304                        x -= x_adj / 2;
305                        y -= y_adj / 2;
306                        break;
307                  }
308               }
309            }
310         }
311      }
312   }
313}
314
315