Skip to content

Commit

Permalink
Added support of lineSpacing for Text & Labeled
Browse files Browse the repository at this point in the history
  • Loading branch information
salmonb committed Dec 9, 2023
1 parent a38e66c commit 5d4bd6c
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ public LabeledText(Labeled labeled) {
this.setFill(this.labeled.getTextFill());
this.setFont(this.labeled.getFont());
this.setTextAlignment(this.labeled.getTextAlignment());
/*
this.setUnderline(this.labeled.isUnderline());
//this.setUnderline(this.labeled.isUnderline());
this.setLineSpacing(this.labeled.getLineSpacing());
*/

//
// Bind the state of this Text object to that of the Labeled.
Expand All @@ -42,10 +40,8 @@ public LabeledText(Labeled labeled) {
this.fontProperty().bind(this.labeled.fontProperty());
// do not bind text - Text doesn't have -fx-text
this.textAlignmentProperty().bind(this.labeled.textAlignmentProperty());
/*
this.underlineProperty().bind(this.labeled.underlineProperty());
//this.underlineProperty().bind(this.labeled.underlineProperty());
this.lineSpacingProperty().bind(this.labeled.lineSpacingProperty());
*/

getStyleClass().addAll("text");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,8 @@ public LabeledSkinBase(final C labeled, final B behavior) {
registerChangeListener(labeled.textAlignmentProperty(), "TEXT_ALIGNMENT");
registerChangeListener(labeled.textOverrunProperty(), "TEXT_OVERRUN");
registerChangeListener(labeled.wrapTextProperty(), "WRAP_TEXT");
/*
registerChangeListener(labeled.underlineProperty(), "UNDERLINE");
//registerChangeListener(labeled.underlineProperty(), "UNDERLINE");
registerChangeListener(labeled.lineSpacingProperty(), "LINE_SPACING");
*/
registerChangeListener(labeled.sceneProperty(), "SCENE");
}

Expand Down Expand Up @@ -729,7 +727,8 @@ private Text getTextToMeasure(Font font, String text, double wrappingWidth) { //
textToMesure = noWrappingText;
} else { // Otherwise using this.text to measure and apply wrapping width & text to it (should be final values to apply for html mapping)
textToMesure = this.text;
//textToMesure.setFont(font); // already bound to font
//textToMesure.setFont(font); // already bound in LabeledText
//textToMesure.setLineSpacing(lineSpacing) // already bound in LabeledText
textToMesure.setWrappingWidth(wrappingWidth);
}
FXProperties.setIfNotEquals(textToMesure.textProperty(), text);
Expand Down Expand Up @@ -789,7 +788,7 @@ private double computeMinLabeledPartHeight(double width, double topInset, double
Utils.boundedSize(graphic.prefWidth(-1), graphic.minWidth(-1), graphic.maxWidth(-1));

// Now add on the graphic, gap, and padding as appropriate
final Node graphic = labeled.getGraphic();
//final Node graphic = labeled.getGraphic();
if (isIgnoreGraphic()) {
return textWidth + widthPadding;
} else if (isIgnoreText()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void bind(N labeled, SceneRequester sceneRequester) {
, node.textAlignmentProperty()
, node.textFillProperty()
, node.wrapTextProperty()
, node.lineSpacingProperty()
);
}

Expand All @@ -34,6 +35,7 @@ public boolean updateProperty(ObservableValue changedProperty) {
|| updateProperty(node.graphicProperty(), changedProperty, mixin::updateGraphic)
|| updateProperty(node.textProperty(), changedProperty, mixin::updateText)
|| updateProperty(node.wrapTextProperty(), changedProperty, mixin::updateWrapText)
|| updateProperty(node.lineSpacingProperty(), changedProperty, mixin::updateLineSpacing)
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public interface LabeledPeerMixin
void updateTextFill(Paint textFill);

void updateWrapText(boolean wrapText);

void updateLineSpacing(Number lineSpacing);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
package dev.webfx.kit.mapper.peers.javafxcontrols.gwt.html;

import elemental2.dom.Element;
import elemental2.dom.HTMLElement;
import javafx.scene.Node;
import javafx.scene.control.Labeled;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import dev.webfx.kit.mapper.peers.javafxcontrols.base.LabeledPeerBase;
import dev.webfx.kit.mapper.peers.javafxcontrols.base.LabeledPeerMixin;
import dev.webfx.kit.mapper.peers.javafxgraphics.gwt.html.HtmlImageViewPeer;
Expand All @@ -15,6 +8,13 @@
import dev.webfx.kit.mapper.peers.javafxgraphics.gwt.util.HtmlPaints;
import dev.webfx.kit.mapper.peers.javafxgraphics.gwt.util.HtmlUtil;
import dev.webfx.platform.util.Strings;
import elemental2.dom.Element;
import elemental2.dom.HTMLElement;
import javafx.scene.Node;
import javafx.scene.control.Labeled;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;

/**
* @author Bruno Salmon
Expand Down Expand Up @@ -91,8 +91,13 @@ public void updateTextFill(Paint textFill) {
public void updateWrapText(boolean wrapText) {
if (doesSkinRelyOnPeerToProvideVisualContent()) { // Note: for LabeledSkinBase, the wrapping is done though its internal Text node having a wrapping width -> see HtmlTextPeer.updateWrappingWidth()
setElementStyleAttribute("white-space", wrapText ? "normal" : "nowrap");
//setElementStyleAttribute("line-height", wrapText ? "normal" : "100%"); // Commented as not sure about line-height: 100% when not wrapping text TODO: investigate the expected height in JavaFX
}
}

@Override
public void updateLineSpacing(Number lineSpacing) {
if (doesSkinRelyOnPeerToProvideVisualContent()) { // Note: for LabeledSkinBase, the wrapping is done though its internal Text node having a line spacing -> see HtmlTextPeer.updateLineSpacing()
// TODO: implement lineSpacing if necessary
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ public DoubleProperty wrappingWidthProperty() {
return wrappingWidthProperty;
}

private final DoubleProperty lineSpacingProperty = new SimpleDoubleProperty(0d);

public DoubleProperty lineSpacingProperty() {
return lineSpacingProperty;
}

public double getLineSpacing() {
return lineSpacingProperty.get();
}

public void setLineSpacing(double lineSpacing) {
this.lineSpacingProperty.set(lineSpacing);
}

private final DoubleProperty yProperty = new SimpleDoubleProperty(0d);
@Override
public DoubleProperty yProperty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void bind(N t, SceneRequester sceneRequester) {
, t.xProperty()
, t.yProperty()
, t.wrappingWidthProperty()
, t.lineSpacingProperty()
, t.textAlignmentProperty()
, t.fontProperty()
, t.textProperty()
Expand All @@ -34,8 +35,10 @@ public boolean updateProperty(ObservableValue changedProperty) {
|| updateProperty(ts.xProperty(), changedProperty, p -> mixin.updateX(p.doubleValue()))
|| updateProperty(ts.yProperty(), changedProperty, p -> mixin.updateY(p.doubleValue()))
|| updateProperty(ts.wrappingWidthProperty(), changedProperty, p -> mixin.updateWrappingWidth(p.doubleValue()))
|| updateProperty(ts.lineSpacingProperty(), changedProperty, mixin::updateLineSpacing)
|| updateProperty(ts.textAlignmentProperty(), changedProperty, mixin::updateTextAlignment)
|| updateProperty(ts.textOriginProperty(), changedProperty, mixin::updateTextOrigin)
|| updateProperty(ts.fontProperty(), changedProperty, mixin::updateFont);
|| updateProperty(ts.fontProperty(), changedProperty, mixin::updateFont)
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public interface TextPeerMixin
void updateY(Double y);

void updateWrappingWidth(Double wrappingWidth);
void updateLineSpacing(Number lineSpacing);

void updateTextAlignment(TextAlignment textAlignment);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void bind(N node, SceneRequester sceneRequester) {

private SVGRect getBBox() {
//if (bBox == null)
bBox = svgTextPeer.getBBox();
bBox = svgTextPeer.getBBox();
return bBox;
}

Expand Down Expand Up @@ -166,6 +166,12 @@ public void updateWrappingWidth(Double wrappingWidth) {
svgTextPeer.updateWrappingWidth(wrappingWidth);
}

@Override
public void updateLineSpacing(Number lineSpacing) {
svgTextPeer.updateLineSpacing(lineSpacing);
updateViewBox();
}

@Override
public void updateTextAlignment(TextAlignment textAlignment) {
svgTextPeer.updateTextAlignment(textAlignment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import dev.webfx.kit.mapper.peers.javafxgraphics.gwt.util.HtmlUtil;
import dev.webfx.platform.uischeduler.UiScheduler;
import dev.webfx.platform.util.Numbers;
import elemental2.dom.CSSProperties;
import elemental2.dom.CSSStyleDeclaration;
import elemental2.dom.HTMLElement;
import javafx.geometry.VPos;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
Expand Down Expand Up @@ -129,12 +131,44 @@ private void updateYInAnimationFrame(boolean sizeChanged) {

@Override
public void updateWrappingWidth(Double wrappingWidth) {
double width = Numbers.doubleValue(wrappingWidth);
if (width != 0)
setElementStyleAttribute("width", toPx(width));
// Setting the wrapping mode in HTML through white-space style attribute
setElementStyleAttribute("white-space", width != 0 ? "normal" : "nowrap");
updateWrappingWithAndLineSpacing(Numbers.doubleValue(wrappingWidth), getNode().getLineSpacing());
}

@Override
public void updateLineSpacing(Number lineSpacing) {
updateWrappingWithAndLineSpacing(getNode().getWrappingWidth(), Numbers.doubleValue(lineSpacing));
}

private void updateWrappingWithAndLineSpacing(double wrappingWidth, double lineSpacing) {
boolean isWrapping = wrappingWidth != 0;
HTMLElement element = getElement();
CSSStyleDeclaration style = element.style;
// First, we set the HTML line height with no extra spacing between lines (lineSpacing = 0).
// Note: it looks like JavaFX doesn't apply the same line height for single-line and multi-lines texts.
// For single-line, it looks like HTML "normal", and for multi-line it looks like 130% (empiric value).
style.lineHeight = CSSProperties.LineHeightUnionType.of(isWrapping ? "130%" : "normal"); // Note: 100% < normal < 130%
// We correct the line height if an additional line spacing is requested
if (isWrapping && lineSpacing != 0) { // not necessary if not wrapping (i.e. single line text)
// There is no HTML equivalent of the JavaFX lineSpacing which specifies only the extra space (expressed in
// pixels) between lines of space (and not the whole line height). So, to map this into HTML, we need to
// 1) get the value of the HTML line height expressed in pixels, and 2) correct it by adding lineSpacing.
// 1) Getting the value of line height in pixels (rather than "normal" or "130%"). To do that, we measure
// the current height of the element for a single line of text.
String currentText = element.textContent; // Memorising the current text (it may be a multi-line text)
element.textContent = "W"; // Temporarily changing the text content to a single letter (=> ensures single-line)
clearCache(); // Clearing the cache to ensure a fresh measurement
double lineHeightPx = measure(element, false); // We mesure the height = line height in pixels
element.textContent = currentText; // Re-establishing the current text
// 2) Correcting the line height by adding the requested line spacing
style.lineHeight = CSSProperties.LineHeightUnionType.of(toPx(lineHeightPx + lineSpacing));
}
// Mapping the wrapping with using the HTML width style attribute
style.width = isWrapping ? CSSProperties.WidthUnionType.of(toPx(wrappingWidth)) : null;
// Mapping the wrapping mode using the HTML white-space style attribute
style.whiteSpace = isWrapping ? "normal" : "nowrap";
// Clearing the measurement cache because HTML attributes have changed
clearCache();
// An update of Y may be necessary (to consider textOrigin)
updateYInAnimationFrame(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public void updateWrappingWidth(Double wrappingWidth) {
updateX();
}

@Override
public void updateLineSpacing(Number lineSpacing) {
// TODO: implement SVG line spacing
}

@Override
public void updateTextAlignment(TextAlignment textAlignment) {
setElementAttribute("text-anchor", textAlignmentToSvgTextAnchor(textAlignment));
Expand Down
6 changes: 6 additions & 0 deletions webfx-kit/webfx-kit-javafxweb-peers-gwt/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
<version>0.1.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>dev.webfx</groupId>
<artifactId>webfx-platform-util</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>

</dependencies>

</project>

0 comments on commit 5d4bd6c

Please sign in to comment.