/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package net.sf.latexdraw.ui;
import com.sun.javafx.tk.FontLoader;
import com.sun.javafx.tk.Toolkit;
import java.util.Arrays;
import javafx.beans.binding.Bindings;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import net.sf.latexdraw.util.LSystem;
/**
* This widgets is a text area that automatically resizes its width and height according to its text.
* @author Arnaud BLOUIN
*/
public class TextAreaAutoSize extends TextArea {
/**
* States whether the text typed in the filed is valid. If not, the background of the filed is painted in red.
* That feature can be used when the text typed needed to be validated.
*/
protected boolean valid;
protected final Text msg = new Text();
/**
* Creates the widget.
*/
public TextAreaAutoSize() {
super();
valid = true;
setOnKeyPressed(evt -> {
if(evt.getCode() == KeyCode.ENTER) {
if(evt.isShiftDown()) {
final int caretPosition = getCaretPosition();
setText(getText() + LSystem.EOL);
positionCaret(caretPosition + 1);
}else {
evt.consume();
}
}
});
textProperty().addListener((observable, oldValue, newValue) -> updateDimension(newValue));
msg.setFocusTraversable(false);
msg.visibleProperty().bind(Bindings.createBooleanBinding(() -> isVisible() && !msg.getText().isEmpty(), visibleProperty()));
msg.setFill(Color.GRAY);
visibleProperty().addListener((observable, oldValue, newValue) -> {
if(newValue) {
updateDimension(getText());
updateBackground();
}
});
msg.layoutXProperty().bind(layoutXProperty());
layoutYProperty().addListener((observable, oldValue, newValue) -> msg.setLayoutY(getLayoutY() + getPrefHeight() + 10));
heightProperty().addListener((observable, oldValue, newValue) -> msg.setLayoutY(getLayoutY() + getPrefHeight() + 10));
updateDimension(getText());
}
/**
* @return The text field that contains a message associated to the text area.
*/
public Text getMessageField() {
return msg;
}
/**
* Defines whether the text typed in the filed is valid. If not, the background of the filed is painted in red.
* That feature can be used when the text typed needed to be validated.
* @param ok Valid or not.
* @since 3.2
*/
public void setValid(final boolean ok) {
valid = ok;
updateBackground();
}
/**
* @return Whether the text typed in the filed is valid.
* @since 3.1
*/
public boolean isValidText() {
return valid;
}
private void updateBackground() {
setBackground(new Background(new BackgroundFill(valid ? Color.WHITE : Color.RED, null, null)));
}
/**
* Updates the size of the widget according to its text.
*/
private void updateDimension(final String newText) {
if(newText==null) return;
final String[] lines = newText.split(LSystem.EOL);
final int countEOL = newText.length() - newText.replace(LSystem.EOL, "").length();
final String maxLine = Arrays.stream(lines).reduce((a, b) -> a.length() > b.length() ? a : b).orElse("");
final Font font = getFont();
final FontLoader fontLoader = Toolkit.getToolkit().getFontLoader();
final double width = fontLoader.computeStringWidth(maxLine + " ", font);
float height = fontLoader.getFontMetrics(font).getLineHeight() * (countEOL + 1) + 15;
setPrefRowCount(countEOL);
setPrefColumnCount(maxLine.length() + 1);
setPrefWidth(width + 25);
setMinWidth(width + 25);
setPrefHeight(height);
setMinHeight(height);
}
}