001 /* Spring.java -- 002 Copyright (C) 2004 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package javax.swing; 039 040 import java.awt.Component; 041 import java.awt.Dimension; 042 043 /** 044 * Calculates the space between component edges, that are layed out by 045 * {@link SpringLayout}. 046 * <p> 047 * A Spring defines a minimum, preferred and maximum distance for each edge 048 * (north, east, south, west) of a component. 049 * </p> 050 * However, springs are not static, their actual values are computed at 051 * runtime. That means, if a Spring C is defined as the sum of Spring A and 052 * Spring B, then the values (min, pref and max) are not calculated at 053 * creation of Spring C, but instead always when {@link #getValue} is 054 * called. So, when Spring A or Spring B changes, this is reflected in 055 * Spring C. 056 * 057 * @author Roman Kennke (roman@ontographics.com) 058 */ 059 public abstract class Spring 060 { 061 062 /** Indicates a not-set value. **/ 063 public static final int UNSET = Integer.MIN_VALUE; 064 065 /** 066 * Creates a new Spring object. This constructor is used by the static 067 * methods which create Springs. 068 */ 069 protected Spring() 070 { 071 // Nothing to do here. 072 } 073 074 /** 075 * Creates a Spring which min, pref and max values are all the same. 076 * These kind of Springs are 'struts'. 077 * 078 * @param val the constant for min, pref and max values. 079 * @return a Spring object with constant values for min, pref and max. 080 */ 081 public static Spring constant(int val) 082 { 083 return new SimpleSpring(val, val, val); 084 } 085 086 /** Creates a Spring which min, pref and max values are constants. 087 * @param min the constant for the minimum value. 088 * @param pref the constant for the preferred value. 089 * @param max the constant for the maximum value. 090 * @return a Spring object with constant values for min, pref and max. 091 */ 092 public static Spring constant(int min, int pref, int max) 093 { 094 return new SimpleSpring(min, pref, max); 095 } 096 097 /** 098 * Returns the maximum value of the Spring. 099 * 100 * @return the maximum value. 101 */ 102 public abstract int getMaximumValue(); 103 104 /** 105 * Returns the minimum value of this Spring. 106 * 107 * @return the minimum value. 108 */ 109 public abstract int getMinimumValue(); 110 111 /** 112 * Return the preferred value of this Spring. 113 * 114 * @return the preferred value. 115 */ 116 public abstract int getPreferredValue(); 117 118 /** 119 * Return the actual value of this Spring. 120 * 121 * @return the actual value of this Spring. 122 */ 123 public abstract int getValue(); 124 125 /** 126 * Creates and returns a Spring, which always has the maximum values 127 * min = max(min_s1, min_s2), pref = max(pref_s1, pref_s2), max = 128 * max(max_s1, max_s2). 129 * 130 * @param s1 the first summand of the max Spring. 131 * @param s2 the second summand of the max Spring. 132 * @return a Spring which is max(s1, s2). 133 */ 134 public static Spring max(Spring s1, Spring s2) 135 { 136 return new MaxSpring(s1, s2); 137 } 138 139 /** 140 * Creates and returns a Spring, which is always the negation of s. 141 * min = -min_s, pref = -pref_s, max = -max_pref. 142 * 143 * @param s the Spring to be negated. 144 * @return the negative of <code>s</code>. 145 */ 146 public static Spring minus(Spring s) 147 { 148 return new MinusSpring(s); 149 } 150 151 /** 152 * Sets the actual value. If <code>value</code> is out of the (min, max) 153 * bounds, then the value is adjusted, so that is inside these bounds. 154 * 155 * @param value the value to be set. 156 */ 157 public abstract void setValue(int value); 158 159 private int getShrinkRange() 160 { 161 return (getPreferredValue() - getMinimumValue()); 162 } 163 164 private int getExpandRange() 165 { 166 return (getMaximumValue() - getPreferredValue()); 167 } 168 169 double getStrain() 170 { 171 int v = getValue(); 172 int p = getPreferredValue(); 173 int r = (v < p) ? getShrinkRange() : getExpandRange(); 174 if (r == 0) 175 r = 1; 176 return (double)(v - p) / r; 177 } 178 179 void setStrain(double strain) 180 { 181 int r = (strain < 0) ? getShrinkRange() : getExpandRange(); 182 int v = (getPreferredValue() + (int)(strain * r)); 183 setValue(v); 184 } 185 186 /** 187 * Creates and returns a Spring, which is always the sum of s1 and s2. 188 * min_sum = min_s1 + min_s2, pref_sum = pref_s1 + pref_s2, max_sum = 189 * max_s1 + max_s2. 190 * 191 * @param s1 the 1st summand of the sum Spring. 192 * @param s2 the 2nd summand of the sum Spring. 193 * @return a sum which is <code>s1 + s2</code>. 194 */ 195 public static Spring sum(Spring s1, Spring s2) 196 { 197 return new AddSpring(s1, s2); 198 } 199 200 /** 201 * Return a new Spring which computes its values by scaling 202 * the values of another spring by a constant factor. If the 203 * factor is negative, the minimum and maximum values of 204 * the argument spring will be interchanged. 205 * @param spring the spring to track 206 * @param factor the factor by which to scale 207 * @return a new multiplicative Spring 208 * @since 1.5 209 */ 210 public static Spring scale(final Spring spring, final float factor) 211 { 212 if (spring == null) 213 throw new NullPointerException("spring argument is null"); 214 return new Spring() 215 { 216 public int getMaximumValue() 217 { 218 return (int) ((factor < 0 ? spring.getMinimumValue() 219 : spring.getMaximumValue()) 220 * factor); 221 } 222 223 public int getMinimumValue() 224 { 225 return (int) ((factor < 0 ? spring.getMaximumValue() 226 : spring.getMinimumValue()) 227 * factor); 228 } 229 230 public int getPreferredValue() 231 { 232 return (int) (spring.getPreferredValue() * factor); 233 } 234 235 public int getValue() 236 { 237 return (int) (spring.getValue() * factor); 238 } 239 240 public void setValue(int value) 241 { 242 spring.setValue((int) (value / factor)); 243 } 244 }; 245 } 246 247 /** 248 * Return a new Spring which takes its values from the specified 249 * Component. In particular, the maximum value is taken from 250 * the maximumSize, the minimum value is taken from the minimumSize, 251 * the preferred value is taken from the preferredSize, and the 252 * value is taken from the component's current size. These values 253 * change as the component changes size. 254 * @param component the component 255 * @return a new Spring which tracks the component's width 256 * @since 1.5 257 */ 258 public static Spring width(final Component component) 259 { 260 return new Spring() 261 { 262 public int getMaximumValue() 263 { 264 return component.getMaximumSize().width; 265 } 266 267 public int getMinimumValue() 268 { 269 return component.getMinimumSize().width; 270 } 271 272 public int getPreferredValue() 273 { 274 return component.getPreferredSize().width; 275 } 276 277 public int getValue() 278 { 279 return component.getSize().width; 280 } 281 282 public void setValue(int value) 283 { 284 Dimension d = component.getSize(); 285 component.setSize(value, d.height); 286 } 287 }; 288 } 289 290 /** 291 * Return a new Spring which takes its values from the specified 292 * Component. In particular, the maximum value is taken from 293 * the maximumSize, the minimum value is taken from the minimumSize, 294 * the preferred value is taken from the preferredSize, and the 295 * value is taken from the component's current size. These values 296 * change as the component changes size. 297 * @param component the component 298 * @return a new Spring which tracks the component's height 299 * @since 1.5 300 */ 301 public static Spring height(final Component component) 302 { 303 return new Spring() 304 { 305 public int getMaximumValue() 306 { 307 return component.getMaximumSize().height; 308 } 309 310 public int getMinimumValue() 311 { 312 return component.getMinimumSize().height; 313 } 314 315 public int getPreferredValue() 316 { 317 return component.getPreferredSize().height; 318 } 319 320 public int getValue() 321 { 322 return component.getSize().height; 323 } 324 325 public void setValue(int value) 326 { 327 Dimension d = component.getSize(); 328 component.setSize(d.width, value); 329 } 330 }; 331 } 332 333 /** 334 * A simple Spring, that holds constant values for min, pref and max. 335 * 336 * @author Roman Kennke (roman@ontographics.com) 337 */ 338 private static final class SimpleSpring extends Spring 339 { 340 341 /** The constant value for min. */ 342 private final int min; 343 344 /** The constant value for pref. */ 345 private final int pref; 346 347 /** The constant value for max. */ 348 private final int max; 349 350 /** The actual value of the spring. */ 351 private int value; 352 353 public String toString() 354 { 355 return "SimpleSpring of " + value; 356 } 357 358 /** 359 * Creates a new SimpleSpring object. 360 * 361 * @param newMin the constant minimum value. 362 * @param newPref the constant preferred value. 363 * @param newMax the constant maximum value. 364 */ 365 public SimpleSpring(int newMin, int newPref, int newMax) 366 { 367 min = newMin; 368 pref = newPref; 369 max = newMax; 370 value = newPref; 371 } 372 373 /** 374 * Returns the maximum value of this Spring. 375 * 376 * @return the maximum value. 377 */ 378 public int getMaximumValue() 379 { 380 return max; 381 } 382 383 /** 384 * Returns the minimum value of this Spring. 385 * 386 * @return the minimum value. 387 */ 388 public int getMinimumValue() 389 { 390 return min; 391 } 392 393 /** 394 * Returns the preferred value of this Spring. 395 * 396 * @return the preferred value. 397 */ 398 public int getPreferredValue() 399 { 400 return pref; 401 } 402 403 /** 404 * Return the actual current value of this Spring. 405 * 406 * @return the current value. 407 */ 408 public int getValue() 409 { 410 if (value == Spring.UNSET) 411 return pref; 412 return value; 413 } 414 415 /** 416 * Sets the current value. 417 * 418 * @param val the value to be set. 419 */ 420 public void setValue(int val) 421 { 422 value = val; 423 } 424 } 425 426 427 /** 428 * A Spring, that is the sum of two other Springs. 429 * 430 * @author Roman Kennke (roman@ontographics.com) 431 */ 432 private static final class AddSpring extends Spring 433 { 434 435 /** The springs, that are the 'operands' of this Spring. */ 436 private final Spring s1; 437 private final Spring s2; 438 439 /** The current value for this Spring. */ 440 private int value; 441 442 public String toString() 443 { 444 return "AddSpring of " + s1 + " and " + s2; 445 } 446 447 /** 448 * Creates a new AddSpring object. 449 * 450 * @param s1 the first operand. 451 * @param s2 the second operand. 452 */ 453 protected AddSpring(Spring s1, Spring s2) 454 { 455 super(); 456 this.s1 = s1; 457 this.s2 = s2; 458 value = Spring.UNSET; 459 } 460 461 /** 462 * Returns the maximum value of this Spring. 463 * 464 * @return the maximum value. 465 */ 466 public int getMaximumValue() 467 { 468 int max1 = s1.getMaximumValue(); 469 int max2 = s2.getMaximumValue(); 470 return max1 + max2; 471 } 472 473 /** 474 * Return the minimum value of this Spring. 475 * 476 * @return the minimum value. 477 */ 478 public int getMinimumValue() 479 { 480 int min1 = s1.getMinimumValue(); 481 int min2 = s2.getMinimumValue(); 482 return min1 + min2; 483 } 484 485 /** 486 * Returns the preferred value of this Spring. 487 * 488 * @return the preferred value. 489 */ 490 public int getPreferredValue() 491 { 492 int pref1 = s1.getPreferredValue(); 493 int pref2 = s2.getPreferredValue(); 494 return pref1 + pref2; 495 } 496 497 /** 498 * Returns the actual current value of this Spring. 499 * 500 * @return the current value of this Spring. 501 */ 502 public int getValue() 503 { 504 if (value == Spring.UNSET) 505 { 506 int val1 = s1.getValue(); 507 int val2 = s2.getValue(); 508 value = val1 + val2; 509 } 510 return value; 511 } 512 513 /** 514 * Sets the current value. 515 * 516 * @param val the value to be set. 517 */ 518 public void setValue(int val) 519 { 520 if (val == Spring.UNSET) 521 { 522 if (value != Spring.UNSET) 523 { 524 s1.setValue(Spring.UNSET); 525 s2.setValue(Spring.UNSET); 526 } 527 value = Spring.UNSET; 528 return; 529 } 530 531 value = val; 532 533 //Spead the value over the two components 534 double fStrain = getStrain(); 535 s1.setStrain(fStrain); 536 int remainder = val - s1.getValue(); 537 s2.setValue(remainder); 538 } 539 540 } 541 542 543 /** 544 * A Spring that is calculated as the negation of another Spring. 545 * 546 * @author Roman Kennke (roman@ontographics.com) 547 */ 548 private static final class MinusSpring extends Spring 549 { 550 551 /** The Spring from which to calculate the negation. */ 552 private final Spring s; 553 554 public String toString() 555 { 556 return "MinusSpring of " + s; 557 } 558 559 /** 560 * Creates a new MinusSpring object. 561 * @param s the Spring from which to calculate the negation. 562 */ 563 protected MinusSpring(Spring s) 564 { 565 super(); 566 this.s = s; 567 } 568 569 /** Returns the maximum value of this Spring. 570 * 571 * @return the maximum value. 572 */ 573 public int getMaximumValue() 574 { 575 return -s.getMinimumValue(); 576 } 577 578 /** 579 * Returns the minimum value of this Spring. 580 * 581 * @return the minimum value. 582 */ 583 public int getMinimumValue() 584 { 585 return -s.getMaximumValue(); 586 } 587 588 /** 589 * Returns the preferred value of this Spring. 590 * 591 * @return the preferred value. 592 */ 593 public int getPreferredValue() 594 { 595 return -s.getPreferredValue(); 596 } 597 598 /** 599 * Returns the current value of this Spring. 600 * 601 * @return the current value. 602 */ 603 public int getValue() 604 { 605 return -s.getValue(); 606 } 607 608 /** 609 * Sets the current value. 610 * 611 * @param val the value to be set. 612 */ 613 public void setValue(int val) 614 { 615 if (val == Spring.UNSET) 616 s.setValue(Spring.UNSET); 617 else 618 s.setValue(-val); 619 } 620 } 621 622 623 /** 624 * A Spring, that is calculated as the maximum of two Springs. 625 * 626 * @author Roman Kennke (roman@ontographics.com) 627 */ 628 private static final class MaxSpring extends Spring 629 { 630 631 /** The two other Springs from which to calculate the maximum. */ 632 private final Spring s1; 633 private final Spring s2; 634 635 public String toString() 636 { 637 return "MaxSpring of " + s1 + " and " + s2; 638 } 639 640 /** The current value of this Spring. */ 641 private int value; 642 643 /** 644 * Creates a new MaxSpring object. 645 * 646 * @param s1 the 1st operand. 647 * @param s2 the 2nd operand. 648 */ 649 protected MaxSpring(Spring s1, Spring s2) 650 { 651 super(); 652 this.s1 = s1; 653 this.s2 = s2; 654 value = Spring.UNSET; 655 } 656 657 658 /** 659 * Returns the maximum value of this Spring. 660 * 661 * @return the maximum value. 662 */ 663 public int getMaximumValue() 664 { 665 int max1 = s1.getMaximumValue(); 666 int max2 = s2.getMaximumValue(); 667 return Math.max(max1, max2); 668 } 669 670 /** 671 * Returns the minimum value of this Spring. 672 * 673 * @return the minimum value. 674 */ 675 public int getMinimumValue() 676 { 677 int min1 = s1.getMinimumValue(); 678 int min2 = s2.getMinimumValue(); 679 return Math.max(min1, min2); 680 } 681 682 /** 683 * Returns the preferred value of this Spring. 684 * 685 * @return the preferred value. 686 */ 687 public int getPreferredValue() 688 { 689 int pref1 = s1.getPreferredValue(); 690 int pref2 = s2.getPreferredValue(); 691 return Math.max(pref1, pref2); 692 } 693 694 /** 695 * Returns the actual value of this Spring. 696 * 697 * @return the current value. 698 */ 699 public int getValue() 700 { 701 if (value == Spring.UNSET) 702 { 703 int val1 = s1.getValue(); 704 int val2 = s2.getValue(); 705 value = Math.max(val1, val2); 706 } 707 return value; 708 } 709 710 /** 711 * Sets the current value. 712 * 713 * @param val the value to be set. 714 */ 715 public void setValue(int val) 716 { 717 if (val == Spring.UNSET) 718 { 719 if (value != Spring.UNSET) 720 { 721 s1.setValue(Spring.UNSET); 722 s2.setValue(Spring.UNSET); 723 } 724 value = Spring.UNSET; 725 return; 726 } 727 728 value = val; 729 730 int p1 = s1.getPreferredValue(); 731 int p2 = s2.getPreferredValue(); 732 733 if (p1 < p2) 734 { 735 s1.setValue(Math.min(val, p1)); 736 s2.setValue(val); 737 } 738 else 739 { 740 s1.setValue(val); 741 s2.setValue(Math.min(val, p2)); 742 } 743 } 744 } 745 }