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