52 * annotations, as well as the overarching 53 * {@link #buttonOrderProperty() button order} specified for the ButtonBar. 54 * 55 * <strong>Uniform button sizing</strong> 56 * <p>By default all buttons are uniformly sized in a ButtonBar, meaning that all 57 * buttons take the width of the widest button. It is possible to opt-out of this 58 * on a per-button basis, but calling the {@link #setButtonUniformSize(Node, boolean)} method with 59 * a boolean value of false. 60 * 61 * <p>If a button is excluded from uniform sizing, it is both excluded from 62 * being resized away from its preferred size, and also excluded from the 63 * measuring process, so its size will not influence the maximum size calculated 64 * for all buttons in the ButtonBar. 65 * 66 * <h3>Screenshots</h3> 67 * <p>Because a ButtonBar comes with built-in support for Windows, Mac OS 68 * and Linux, there are three screenshots shown below, with the same buttons 69 * laid out on each of the three operating systems. 70 * 71 * <p> 72 * <strong>Windows:</strong><br/><img src="doc-files/buttonBar-windows.png" /><br> 73 * <strong>Mac OS:</strong><br/><img src="doc-files/buttonBar-mac.png" /><br> 74 * <strong>Linux:</strong><br/><img src="doc-files/buttonBar-linux.png" /><br> 75 * 76 * <h3>Code Samples</h3> 77 * <p>Instantiating and using the ButtonBar is simple, simply do the following: 78 * 79 * <pre> 80 * {@code 81 * // Create the ButtonBar instance 82 * ButtonBar buttonBar = new ButtonBar(); 83 * 84 * // Create the buttons to go into the ButtonBar 85 * Button yesButton = new Button("Yes"); 86 * ButtonBar.setButtonData(yesButton, ButtonData.YES); 87 * 88 * Button noButton = new Button("No"); 89 * ButtonBar.setButtonData(noButton, ButtonData.NO); 90 * 91 * // Add buttons to the ButtonBar 92 * buttonBar.getButtons().addAll(yesButton, noButton); 93 * }</pre> 94 * 95 * <p>The code sample above will position the Yes and No buttons relative to the 96 * users operating system. This means that on Windows and Linux the Yes button 97 * will come before the No button, whereas on Mac OS it'll be No and then Yes. 98 * 99 * <p>In most cases the OS-specific layout is the best choice, but in cases 100 * where you want a custom layout, this is achieved be modifying the 101 * {@link #buttonOrderProperty() button order property}. These are cryptic-looking 102 * strings that are shorthand representations for the button order. The built-in 103 * orders for Windows, Mac OS and Linux are: 104 * 105 * <table border="0"> 106 * <tr> 107 * <td width="75"><strong>Windows:</strong></td> 108 * <td>L_E+U+FBXI_YNOCAH_R</td> 109 * </tr> 110 * <tr> 111 * <td><strong>Mac OS:</strong></td> 112 * <td>L_HE+U+FBIX_NCYOA_R</td> 113 * </tr> 114 * <tr> 115 * <td><strong>Linux:</strong></td> 116 * <td>L_HE+UNYACBXIO_R</td> 117 * </tr> 118 * </table> 119 * 120 * <p>You should refer to the {@link ButtonData} enumeration for a description of 121 * what each of these characters mean. However, if your ButtonBar only consisted 122 * of {@link ButtonData#YES} and {@link ButtonData#NO} buttons, you always 123 * wanted the yes buttons before the no buttons, and you wanted the buttons to 124 * be {@link ButtonData#BIG_GAP right-aligned}, you could do the following: 125 * 126 * <pre> 127 * {@code 300 * 301 * <p><strong>Button order code:</strong> _ (underscore) 302 */ 303 SMALL_GAP("_", false, false); //$NON-NLS-1$ 304 305 private final String typeCode; 306 307 private final boolean cancelButton; 308 private final boolean defaultButton; 309 310 private ButtonData(String type, boolean cancelButton, boolean defaultButton) { 311 this.typeCode = type; 312 this.cancelButton = cancelButton; 313 this.defaultButton = defaultButton; 314 } 315 316 /** 317 * Returns the single character code used to represent the ButtonData 318 * annotation in the {@link ButtonBar#buttonOrderProperty() button order} 319 * string. 320 */ 321 public String getTypeCode() { 322 return typeCode; 323 } 324 325 /** 326 * Indicates whether buttons created from the ButtonData enumeration 327 * should be the 'cancel' button in the user interface. This typically 328 * means that the button will respond to the escape key press, even if 329 * the button does not have focus. 330 * 331 * <p>ButtonData enumeration values that can be the cancel button have a 332 * comment stating this in their javadoc. 333 */ 334 public final boolean isCancelButton() { 335 return cancelButton; 336 } 337 338 /** 339 * Indicates whether buttons created from the ButtonData enumeration 340 * should be the 'default' button in the user interface. This typically 341 * means that the button will respond to enter key presses, even if the 342 * button does not have focus. 343 * 344 * <p>ButtonData enumeration values that can be the default button have 345 * a comment stating this in their javadoc. 346 */ 347 public final boolean isDefaultButton() { 348 return defaultButton; 349 } 350 } 351 352 353 /** 354 * Sets the given ButtonData on the given button. If this button is 355 * subsequently placed in a {@link ButtonBar} it will be placed in the 356 * correct position relative to all other buttons in the bar. 357 * 358 * @param button The button to annotate with the given {@link ButtonData} value. 359 * @param buttonData The ButtonData to designate the button as. 360 */ 361 public static void setButtonData(Node button, ButtonData buttonData) { 362 final Map<Object,Object> properties = button.getProperties(); 363 final ObjectProperty<ButtonData> property = 364 (ObjectProperty<ButtonData>) properties.getOrDefault( 365 Properties.BUTTON_DATA_PROPERTY, 366 new SimpleObjectProperty<>(button, "buttonData", buttonData)); 367 368 property.set(buttonData); 369 properties.putIfAbsent(Properties.BUTTON_DATA_PROPERTY, property); 370 } 371 372 /** 373 * Returns the previously set ButtonData property on the given button. If this 374 * was never set, this method will return null. 375 * 376 * @param button The button to return the previously set ButtonData for. 377 */ 378 public static ButtonData getButtonData(Node button) { 379 final Map<Object,Object> properties = button.getProperties(); 380 if (properties.containsKey(Properties.BUTTON_DATA_PROPERTY)) { 381 ObjectProperty<ButtonData> property = (ObjectProperty<ButtonData>) properties.get(Properties.BUTTON_DATA_PROPERTY); 382 return property == null ? null : property.get(); 383 } 384 return null; 385 } 386 387 /** 388 * By default all buttons are uniformly sized in a ButtonBar, meaning that all 389 * buttons take the width of the widest button. It is possible to opt-out of this 390 * on a per-button basis, but calling the setButtonUniformSize method with 391 * a boolean value of false. 392 * 393 * <p>If a button is excluded from uniform sizing, it is both excluded from 394 * being resized away from its preferred size, and also excluded from the 395 * measuring process, so its size will not influence the maximum size calculated 396 * for all buttons in the ButtonBar. 397 * 398 * @param button The button to include / exclude from uniform sizing. 399 * @param uniformSize Boolean true to force uniform sizing on the button, 400 * false to exclude the button from uniform sizing. 401 */ 402 public static void setButtonUniformSize(Node button, boolean uniformSize) { 403 // we store the false, but remove the true (as the isButtonUniformSize 404 // method returns true by default) 405 if (uniformSize) { 406 button.getProperties().remove(Properties.BUTTON_SIZE_INDEPENDENCE); 407 } else { 408 button.getProperties().put(Properties.BUTTON_SIZE_INDEPENDENCE, uniformSize); 409 } 410 } 411 412 /** 413 * Returns whether the given node is part of the uniform sizing calculations 414 * or not. By default all nodes that have not opted out (via 415 * {@link #setButtonUniformSize(Node, boolean)}) will return true here. 416 */ 417 public static boolean isButtonUniformSize(Node button) { 418 return (boolean) button.getProperties().getOrDefault(Properties.BUTTON_SIZE_INDEPENDENCE, true); 419 } 420 421 422 423 /************************************************************************** 424 * 425 * Private fields 426 * 427 **************************************************************************/ 428 429 private ObservableList<Node> buttons = FXCollections.<Node>observableArrayList(); 430 431 432 433 /************************************************************************** 434 * 435 * Constructors 502 * allowing for further buttons to be added or removed. 503 */ 504 public final ObservableList<Node> getButtons() { 505 return buttons; 506 } 507 508 509 510 /************************************************************************** 511 * 512 * Properties 513 * 514 **************************************************************************/ 515 516 // --- Button order 517 /** 518 * The order for the typical buttons in a standard button bar. It is 519 * one letter per {@link ButtonData} enumeration value. Default button orders 520 * for operating systems are also available: {@link #BUTTON_ORDER_WINDOWS}, 521 * {@link #BUTTON_ORDER_MAC_OS}, and {@link #BUTTON_ORDER_LINUX}. 522 */ 523 public final StringProperty buttonOrderProperty() { 524 return buttonOrderProperty; 525 } 526 private final StringProperty buttonOrderProperty = 527 new SimpleStringProperty(this, "buttonOrder"); //$NON-NLS-1$ 528 529 /** 530 * Sets the {@link #buttonOrderProperty() button order} 531 * @param buttonOrder The currently set button order, which by default will 532 * be the OS-specific button order. 533 */ 534 public final void setButtonOrder(String buttonOrder) { 535 buttonOrderProperty.set(buttonOrder); 536 } 537 538 /** 539 * Returns the current {@link #buttonOrderProperty() button order}. 540 * @return The current {@link #buttonOrderProperty() button order}. 541 */ 542 public final String getButtonOrder() { 543 return buttonOrderProperty.get(); 544 } 545 546 547 // --- button min width 548 /** 549 * Specifies the minimum width of all buttons placed in this button bar. 550 */ 551 public final DoubleProperty buttonMinWidthProperty() { 552 return buttonMinWidthProperty; 553 } 554 private final DoubleProperty buttonMinWidthProperty = 555 new SimpleDoubleProperty(this, "buttonMinWidthProperty"); //$NON-NLS-1$ 556 557 /** 558 * Sets the minimum width of all buttons placed in this button bar. 559 */ 560 public final void setButtonMinWidth(double value) { 561 buttonMinWidthProperty.set(value); 562 } 563 564 /** 565 * Returns the minimum width of all buttons placed in this button bar. 566 */ 567 public final double getButtonMinWidth() { 568 return buttonMinWidthProperty.get(); 569 } 570 571 572 573 /************************************************************************** 574 * 575 * Implementation 576 * 577 **************************************************************************/ 578 579 /** 580 * Returns the initial focus traversable state of this control, for use 581 * by the JavaFX CSS engine to correctly set its initial value. This method 582 * is overridden as by default UI controls have focus traversable set to true, 583 * but that is not appropriate for this control. 584 * 585 * @since 9 | 52 * annotations, as well as the overarching 53 * {@link #buttonOrderProperty() button order} specified for the ButtonBar. 54 * 55 * <strong>Uniform button sizing</strong> 56 * <p>By default all buttons are uniformly sized in a ButtonBar, meaning that all 57 * buttons take the width of the widest button. It is possible to opt-out of this 58 * on a per-button basis, but calling the {@link #setButtonUniformSize(Node, boolean)} method with 59 * a boolean value of false. 60 * 61 * <p>If a button is excluded from uniform sizing, it is both excluded from 62 * being resized away from its preferred size, and also excluded from the 63 * measuring process, so its size will not influence the maximum size calculated 64 * for all buttons in the ButtonBar. 65 * 66 * <h3>Screenshots</h3> 67 * <p>Because a ButtonBar comes with built-in support for Windows, Mac OS 68 * and Linux, there are three screenshots shown below, with the same buttons 69 * laid out on each of the three operating systems. 70 * 71 * <p> 72 * <strong>Windows:</strong><p><img src="doc-files/buttonBar-windows.png" alt=""></p> 73 * <strong>Mac OS:</strong><p><img src="doc-files/buttonBar-mac.png" alt=""></p> 74 * <strong>Linux:</strong><p><img src="doc-files/buttonBar-linux.png" alt=""></p> 75 * 76 * <h3>Code Samples</h3> 77 * <p>Instantiating and using the ButtonBar is simple, simply do the following: 78 * 79 * <pre> 80 * {@code 81 * // Create the ButtonBar instance 82 * ButtonBar buttonBar = new ButtonBar(); 83 * 84 * // Create the buttons to go into the ButtonBar 85 * Button yesButton = new Button("Yes"); 86 * ButtonBar.setButtonData(yesButton, ButtonData.YES); 87 * 88 * Button noButton = new Button("No"); 89 * ButtonBar.setButtonData(noButton, ButtonData.NO); 90 * 91 * // Add buttons to the ButtonBar 92 * buttonBar.getButtons().addAll(yesButton, noButton); 93 * }</pre> 94 * 95 * <p>The code sample above will position the Yes and No buttons relative to the 96 * users operating system. This means that on Windows and Linux the Yes button 97 * will come before the No button, whereas on Mac OS it'll be No and then Yes. 98 * 99 * <p>In most cases the OS-specific layout is the best choice, but in cases 100 * where you want a custom layout, this is achieved be modifying the 101 * {@link #buttonOrderProperty() button order property}. These are cryptic-looking 102 * strings that are shorthand representations for the button order. The built-in 103 * orders for Windows, Mac OS and Linux are: 104 * 105 * <table border="0" summary=""> 106 * <tr> 107 * <td><strong>Windows:</strong></td> 108 * <td>L_E+U+FBXI_YNOCAH_R</td> 109 * </tr> 110 * <tr> 111 * <td><strong>Mac OS:</strong></td> 112 * <td>L_HE+U+FBIX_NCYOA_R</td> 113 * </tr> 114 * <tr> 115 * <td><strong>Linux:</strong></td> 116 * <td>L_HE+UNYACBXIO_R</td> 117 * </tr> 118 * </table> 119 * 120 * <p>You should refer to the {@link ButtonData} enumeration for a description of 121 * what each of these characters mean. However, if your ButtonBar only consisted 122 * of {@link ButtonData#YES} and {@link ButtonData#NO} buttons, you always 123 * wanted the yes buttons before the no buttons, and you wanted the buttons to 124 * be {@link ButtonData#BIG_GAP right-aligned}, you could do the following: 125 * 126 * <pre> 127 * {@code 300 * 301 * <p><strong>Button order code:</strong> _ (underscore) 302 */ 303 SMALL_GAP("_", false, false); //$NON-NLS-1$ 304 305 private final String typeCode; 306 307 private final boolean cancelButton; 308 private final boolean defaultButton; 309 310 private ButtonData(String type, boolean cancelButton, boolean defaultButton) { 311 this.typeCode = type; 312 this.cancelButton = cancelButton; 313 this.defaultButton = defaultButton; 314 } 315 316 /** 317 * Returns the single character code used to represent the ButtonData 318 * annotation in the {@link ButtonBar#buttonOrderProperty() button order} 319 * string. 320 * @return the single character code used to represent the ButtonData 321 * annotation 322 */ 323 public String getTypeCode() { 324 return typeCode; 325 } 326 327 /** 328 * Indicates whether buttons created from the ButtonData enumeration 329 * should be the 'cancel' button in the user interface. This typically 330 * means that the button will respond to the escape key press, even if 331 * the button does not have focus. 332 * 333 * <p>ButtonData enumeration values that can be the cancel button have a 334 * comment stating this in their javadoc. 335 * @return true if this is a 'cancel' button 336 */ 337 public final boolean isCancelButton() { 338 return cancelButton; 339 } 340 341 /** 342 * Indicates whether buttons created from the ButtonData enumeration 343 * should be the 'default' button in the user interface. This typically 344 * means that the button will respond to enter key presses, even if the 345 * button does not have focus. 346 * 347 * <p>ButtonData enumeration values that can be the default button have 348 * a comment stating this in their javadoc. 349 * @return true if this is a 'default' button 350 */ 351 public final boolean isDefaultButton() { 352 return defaultButton; 353 } 354 } 355 356 357 /** 358 * Sets the given ButtonData on the given button. If this button is 359 * subsequently placed in a {@link ButtonBar} it will be placed in the 360 * correct position relative to all other buttons in the bar. 361 * 362 * @param button The button to annotate with the given {@link ButtonData} value. 363 * @param buttonData The ButtonData to designate the button as. 364 */ 365 public static void setButtonData(Node button, ButtonData buttonData) { 366 final Map<Object,Object> properties = button.getProperties(); 367 final ObjectProperty<ButtonData> property = 368 (ObjectProperty<ButtonData>) properties.getOrDefault( 369 Properties.BUTTON_DATA_PROPERTY, 370 new SimpleObjectProperty<>(button, "buttonData", buttonData)); 371 372 property.set(buttonData); 373 properties.putIfAbsent(Properties.BUTTON_DATA_PROPERTY, property); 374 } 375 376 /** 377 * Returns the previously set ButtonData property on the given button. If this 378 * was never set, this method will return null. 379 * 380 * @param button The button to return the previously set ButtonData for. 381 * @return the previously set ButtonData property on the given button 382 */ 383 public static ButtonData getButtonData(Node button) { 384 final Map<Object,Object> properties = button.getProperties(); 385 if (properties.containsKey(Properties.BUTTON_DATA_PROPERTY)) { 386 ObjectProperty<ButtonData> property = (ObjectProperty<ButtonData>) properties.get(Properties.BUTTON_DATA_PROPERTY); 387 return property == null ? null : property.get(); 388 } 389 return null; 390 } 391 392 /** 393 * By default all buttons are uniformly sized in a ButtonBar, meaning that all 394 * buttons take the width of the widest button. It is possible to opt-out of this 395 * on a per-button basis, but calling the setButtonUniformSize method with 396 * a boolean value of false. 397 * 398 * <p>If a button is excluded from uniform sizing, it is both excluded from 399 * being resized away from its preferred size, and also excluded from the 400 * measuring process, so its size will not influence the maximum size calculated 401 * for all buttons in the ButtonBar. 402 * 403 * @param button The button to include / exclude from uniform sizing. 404 * @param uniformSize Boolean true to force uniform sizing on the button, 405 * false to exclude the button from uniform sizing. 406 */ 407 public static void setButtonUniformSize(Node button, boolean uniformSize) { 408 // we store the false, but remove the true (as the isButtonUniformSize 409 // method returns true by default) 410 if (uniformSize) { 411 button.getProperties().remove(Properties.BUTTON_SIZE_INDEPENDENCE); 412 } else { 413 button.getProperties().put(Properties.BUTTON_SIZE_INDEPENDENCE, uniformSize); 414 } 415 } 416 417 /** 418 * Returns whether the given node is part of the uniform sizing calculations 419 * or not. By default all nodes that have not opted out (via 420 * {@link #setButtonUniformSize(Node, boolean)}) will return true here. 421 * @param button the button 422 * @return true if button is part of the uniform sizing calculations 423 */ 424 public static boolean isButtonUniformSize(Node button) { 425 return (boolean) button.getProperties().getOrDefault(Properties.BUTTON_SIZE_INDEPENDENCE, true); 426 } 427 428 429 430 /************************************************************************** 431 * 432 * Private fields 433 * 434 **************************************************************************/ 435 436 private ObservableList<Node> buttons = FXCollections.<Node>observableArrayList(); 437 438 439 440 /************************************************************************** 441 * 442 * Constructors 509 * allowing for further buttons to be added or removed. 510 */ 511 public final ObservableList<Node> getButtons() { 512 return buttons; 513 } 514 515 516 517 /************************************************************************** 518 * 519 * Properties 520 * 521 **************************************************************************/ 522 523 // --- Button order 524 /** 525 * The order for the typical buttons in a standard button bar. It is 526 * one letter per {@link ButtonData} enumeration value. Default button orders 527 * for operating systems are also available: {@link #BUTTON_ORDER_WINDOWS}, 528 * {@link #BUTTON_ORDER_MAC_OS}, and {@link #BUTTON_ORDER_LINUX}. 529 * @return the button order property 530 */ 531 public final StringProperty buttonOrderProperty() { 532 return buttonOrderProperty; 533 } 534 private final StringProperty buttonOrderProperty = 535 new SimpleStringProperty(this, "buttonOrder"); //$NON-NLS-1$ 536 537 /** 538 * Sets the {@link #buttonOrderProperty() button order} 539 * @param buttonOrder The currently set button order, which by default will 540 * be the OS-specific button order. 541 */ 542 public final void setButtonOrder(String buttonOrder) { 543 buttonOrderProperty.set(buttonOrder); 544 } 545 546 /** 547 * Returns the current {@link #buttonOrderProperty() button order}. 548 * @return The current {@link #buttonOrderProperty() button order}. 549 */ 550 public final String getButtonOrder() { 551 return buttonOrderProperty.get(); 552 } 553 554 555 // --- button min width 556 /** 557 * Specifies the minimum width of all buttons placed in this button bar. 558 * @return the minimum width property 559 */ 560 public final DoubleProperty buttonMinWidthProperty() { 561 return buttonMinWidthProperty; 562 } 563 private final DoubleProperty buttonMinWidthProperty = 564 new SimpleDoubleProperty(this, "buttonMinWidthProperty"); //$NON-NLS-1$ 565 566 /** 567 * Sets the minimum width of all buttons placed in this button bar. 568 * @param value the minimum width value 569 */ 570 public final void setButtonMinWidth(double value) { 571 buttonMinWidthProperty.set(value); 572 } 573 574 /** 575 * Returns the minimum width of all buttons placed in this button bar. 576 * @return the minimum width value 577 */ 578 public final double getButtonMinWidth() { 579 return buttonMinWidthProperty.get(); 580 } 581 582 583 584 /************************************************************************** 585 * 586 * Implementation 587 * 588 **************************************************************************/ 589 590 /** 591 * Returns the initial focus traversable state of this control, for use 592 * by the JavaFX CSS engine to correctly set its initial value. This method 593 * is overridden as by default UI controls have focus traversable set to true, 594 * but that is not appropriate for this control. 595 * 596 * @since 9 |