From 705eca4166d07583ce895063f8908ca036a5adf0 Mon Sep 17 00:00:00 2001 From: Jurgen Date: Sat, 11 Jan 2020 21:44:19 +0200 Subject: [PATCH] Added convenient text field alignment capabilities (#896) --- .../fxmisc/richtext/InlineCssTextField.java | 6 ++ .../richtext/StyleClassedTextField.java | 8 +++ .../org/fxmisc/richtext/StyledTextField.java | 59 +++++++++++++++---- .../richtext/styled-text-field-caspian.css | 23 ++++++-- .../richtext/styled-text-field-modena.css | 21 ++++++- 5 files changed, 100 insertions(+), 17 deletions(-) diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/InlineCssTextField.java b/richtextfx/src/main/java/org/fxmisc/richtext/InlineCssTextField.java index c27369148..120e2ab2b 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/InlineCssTextField.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/InlineCssTextField.java @@ -2,6 +2,7 @@ import org.fxmisc.richtext.model.SimpleEditableStyledDocument; +import javafx.scene.text.TextAlignment; import javafx.scene.text.TextFlow; /** @@ -20,4 +21,9 @@ public InlineCssTextField( String text ) { getUndoManager().forgetHistory(); getUndoManager().mark(); } + + @Override + protected void changeAlignment( TextAlignment txtAlign ) { + setParagraphStyle( 0, "-fx-text-alignment: "+ txtAlign ); + } } diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/StyleClassedTextField.java b/richtextfx/src/main/java/org/fxmisc/richtext/StyleClassedTextField.java index 6876beff4..a0580839f 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/StyleClassedTextField.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/StyleClassedTextField.java @@ -5,6 +5,8 @@ import org.fxmisc.richtext.model.SimpleEditableStyledDocument; +import javafx.scene.text.TextAlignment; + /** * A TextField that uses style classes, i.e. getStyleClass().add(String), to define the styles of text segments. *

Use CSS Style Class ".styled-text-field" for styling the control. @@ -55,4 +57,10 @@ public void replace( int start, int end, String text, String styleClass ) { public void setStyleClass( int from, int to, String styleClass ) { setStyle( from, to, Collections.singletonList( styleClass ) ); } + + @Override + protected void changeAlignment( TextAlignment txtAlign ) { + // Set to style class as defined in "styled-text-field-caspian.css" AND "styled-text-field-modena.css" + setParagraphStyle( 0, Collections.singletonList( txtAlign.toString().toLowerCase() ) ); + } } diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/StyledTextField.java b/richtextfx/src/main/java/org/fxmisc/richtext/StyledTextField.java index 0232d5a8f..ad4ad41c5 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/StyledTextField.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/StyledTextField.java @@ -1,5 +1,7 @@ package org.fxmisc.richtext; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import java.util.regex.Pattern; @@ -10,6 +12,10 @@ import javafx.beans.NamedArg; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectPropertyBase; +import javafx.css.CssMetaData; +import javafx.css.StyleConverter; +import javafx.css.Styleable; +import javafx.css.StyleableObjectProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.AccessibleRole; @@ -22,6 +28,7 @@ import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; +import javafx.scene.text.TextAlignment; import javafx.scene.text.TextFlow; /** @@ -29,14 +36,22 @@ * will be styled is not yet specified in this class, but use {@link StyleClassedTextField} for a style class * approach to styling the text and {@link InlineCssTextField} for an inline css approach to styling the text. * + *

Use CSS Style Class ".styled-text-field" for styling the control.

+ * * @param type of paragraph style * @param type of style that can be applied to text. * * @author Jurgen */ -public class StyledTextField extends StyledTextArea +public abstract class StyledTextField extends StyledTextArea { - private final Pattern VERTICAL_WHITESPACE = Pattern.compile( "\\v+" ); + private final static List> CSS_META_DATA_LIST; + + private final static CssMetaData TEXT_ALIGNMENT = new CustomCssMetaData<>( + "-fx-alignment", (StyleConverter) StyleConverter.getEnumConverter(TextAlignment.class), + TextAlignment.LEFT, s -> (StyleableObjectProperty) s.textAlignmentProperty() + ); + private final static Pattern VERTICAL_WHITESPACE = Pattern.compile( "\\v+" ); private final static String STYLE_SHEET; private final static double HEIGHT; static { @@ -46,6 +61,9 @@ public class StyledTextField extends StyledTextArea globalCSS = "styled-text-field-"+ globalCSS.toLowerCase() +".css"; STYLE_SHEET = StyledTextField.class.getResource( globalCSS ).toExternalForm(); + List> styleables = new ArrayList<>(GenericStyledArea.getClassCssMetaData()); + styleables.add(TEXT_ALIGNMENT); CSS_META_DATA_LIST = Collections.unmodifiableList(styleables); + // Ugly hack to get a TextFields default height :( // as it differs between Caspian, Modena, etc. TextField tf = new TextField( "GetHeight" ); @@ -54,6 +72,7 @@ public class StyledTextField extends StyledTextArea } private boolean selectAll = true; + private StyleableObjectProperty textAlignment; public StyledTextField(@NamedArg("initialParagraphStyle") PS initialParagraphStyle, @@ -76,7 +95,7 @@ public StyledTextField(@NamedArg("initialParagraphStyle") PS initialParagraphSty KE.consume(); } else if ( KE.getCode() == KeyCode.TAB ) { - traverse( this.getParent(), this, KE.isShiftDown() ? -1 : +1 ); + traverse( this.getParent(), this, KE.isShiftDown() ? -1 : +1 ); KE.consume(); } }); @@ -136,16 +155,23 @@ else if ( target.isVisible() && ! target.isDisabled() && target.isFocusTraversab return traverse( p.getParent(), p, dir ); // up } - - public void setText( String text ) - { - replaceText( text ); + /** + * Specifies how the text should be aligned when there is empty space within the TextField. + * To configure via CSS use {@code -fx-alignment:} and values from {@link javafx.scene.text.TextAlignment}. + */ + public final ObjectProperty textAlignmentProperty() { + if (textAlignment == null) { + textAlignment = new CustomStyleableProperty<>( TextAlignment.LEFT, "textAlignment", this, TEXT_ALIGNMENT ); + textAlignment.addListener( (ob,ov,alignment) -> changeAlignment( alignment ) ); + } + return textAlignment; } + public final TextAlignment getAlignment() { return textAlignment == null ? TextAlignment.LEFT : textAlignment.getValue(); } + public final void setAlignment( TextAlignment value ) { textAlignmentProperty().setValue( value ); } + protected abstract void changeAlignment( TextAlignment txtAlign ); /** - * The action handler associated with this text field, or - * {@code null} if no action handler is assigned. - * + * The action handler associated with this text field, or {@code null} if no action handler is assigned. * The action handler is normally called when the user types the ENTER key. */ private ObjectProperty> onAction = new ObjectPropertyBase>() { @@ -174,8 +200,21 @@ public void replaceText( int start, int end, String text ) super.replaceText( start, end, VERTICAL_WHITESPACE.matcher( text ).replaceAll( " " ) ); } + public void setText( String text ) + { + replaceText( text ); + } + /** This is a no op for text fields and therefore marked as deprecated. */ @Override @Deprecated public void setWrapText( boolean value ) {} /** This always returns false for styled text fields. */ @Override public boolean isWrapText() { return false; } + + + @Override public List> getCssMetaData() { + return CSS_META_DATA_LIST; + } + public static List> getClassCssMetaData() { + return CSS_META_DATA_LIST; + } } diff --git a/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-caspian.css b/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-caspian.css index 9ddd8ce69..fc1530320 100644 --- a/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-caspian.css +++ b/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-caspian.css @@ -1,7 +1,7 @@ .styled-text-field { -fx-cursor: text; - -fx-text-fill: -fx-text-inner-color; + -fx-text-fill: -fx-text-inner-color; -fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background; -fx-background-insets: 0, 1, 2; -fx-background-radius: 3, 2, 2; @@ -15,9 +15,24 @@ } .styled-text-field:disabled { - -fx-opacity: -fx-disabled-opacity; + -fx-opacity: -fx-disabled-opacity; } -.styled-text-field .main-selection +.main-selection { - -fx-fill: #0093ff; + -fx-fill: #0093ff; +} + +// Text alignment classes for StyleClassedTextField + +.center +{ + -fx-text-alignment: center; +} +.left +{ + -fx-text-alignment: left; +} +.right +{ + -fx-text-alignment: right; } diff --git a/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-modena.css b/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-modena.css index 62b070a88..af1acb3f3 100644 --- a/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-modena.css +++ b/richtextfx/src/main/resources/org/fxmisc/richtext/styled-text-field-modena.css @@ -17,9 +17,24 @@ } .styled-text-field:disabled { - -fx-opacity: 0.4; + -fx-opacity: 0.4; } -.styled-text-field .main-selection +.main-selection { - -fx-fill: #0096C9; + -fx-fill: #0096C9; +} + +// Text alignment classes for StyleClassedTextField + +.center +{ + -fx-text-alignment: center; +} +.left +{ + -fx-text-alignment: left; +} +.right +{ + -fx-text-alignment: right; }