// Path: src/main/java/tornadofx/control/skin/MultiSelectSkin.java
// public class MultiSelectSkin<E> extends SkinBase<MultiSelect<E>> {
// 
// 	public MultiSelectSkin(MultiSelect<E> control) {
// 		super(control);
// 	}
// 
// 	private double getPrefRowHeight() {
// 		double editorHeight = getSkinnable().getEditor().prefHeight(-1);
// 		if (getChildren().isEmpty())
// 			return editorHeight;
// 		else
// 			return Math.max(editorHeight, getChildren().get(0).prefHeight(-1));
// 	}
// 
// 	/**
// 	 * Compute pref width by placing equal amount of childen on each line, with a line height equal to the editors preferred
// 	 * height plus the vgap. This will not be correct in every case, depending on the difference in the other childrens
// 	 * preferred width, but it seems to be adequate.
// 	 */
// 	protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		MultiSelect<E> control = getSkinnable();
// 
// 		double hgap = control.getHgap().doubleValue();
// 		double vgap = control.getVgap().doubleValue();
// 		double prefRowHeight = getPrefRowHeight();
// 
// 		int childCount = getChildren().size();
// 		int rows = height <= 0 ? 1 : (int) Math.max(1, Math.floor((prefRowHeight + vgap) / height));
// 		int perRow = (int) Math.ceil(childCount / rows);
// 
// 		double widestRow = 0;
// 		int childPos = 0;
// 		for (int rowCount = 0; rowCount < rows; rowCount++) {
// 			double rowWidth = 0;
// 			double childPosInRow = 0;
// 
// 			while (childPosInRow < perRow && childPos < childCount) {
// 				Node child = getChildren().get(childPos);
// 				rowWidth += child.prefWidth(prefRowHeight) + hgap;
// 				childPos++;
// 				childPosInRow++;
// 			}
// 
// 			if (rowWidth > widestRow)
// 				widestRow = rowWidth;
// 		}
// 
// 		return widestRow + leftInset + rightInset - hgap;
// 	}
// 
// 	protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		return computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
// 	}
// 
// 	protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		MultiSelect<E> control = getSkinnable();
// 
// 		double usedLineWidth = 0;
// 		double hgap = control.getHgap().doubleValue();
// 		double vgap = control.getVgap().doubleValue();
// 		double prefHeight = getPrefRowHeight();
// 
// 		double y = prefHeight;
// 		if (width == -1 && control.getWidth() > 0)
// 			width = control.getWidth();
// 
// 		for (Node node : getChildren()) {
// 			double prefWidth = node.prefWidth(prefHeight);
// 			if (width > 0 && usedLineWidth + prefWidth > width && usedLineWidth > 0) {
// 				usedLineWidth = 0;
// 				y += prefHeight + vgap;
// 			}
// 			usedLineWidth += prefWidth + hgap;
// 		}
// 
// 		return y;
// 	}
// 
// 	protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
// 		double usedLineWidth = 0;
// 		double hgap = getSkinnable().getHgap().doubleValue();
// 		double vgap = getSkinnable().getVgap().doubleValue();
// 		double prefHeight = getPrefRowHeight();
// 
// 		for (Node node : getChildren()) {
// 			double prefWidth = node.prefWidth(prefHeight);
// 			if (usedLineWidth + prefWidth > contentWidth && usedLineWidth > 0) {
// 				usedLineWidth = 0;
// 				contentY += prefHeight + vgap;
// 			}
// 			double x = usedLineWidth + contentX;
// 			node.resizeRelocate(x, contentY, prefWidth, prefHeight);
// 			usedLineWidth += prefWidth + hgap;
// 		}
// 	}
// 
// }


import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableProperty;
import javafx.css.StyleablePropertyFactory;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import javafx.util.StringConverter;
import tornadofx.control.skin.MultiSelectSkin;
import java.util.List;
import java.util.function.BiFunction;
					getChildren().remove(c.getFrom(), c.getTo() + 1);

				if (c.wasAdded()) {
					for (int i = 0; i < c.getAddedSize(); i++) {
						E item = c.getAddedSubList().get(i);
						Node cell = getCellFactory().apply(this, item);
						getChildren().add(i + c.getFrom(), cell);
					}
				}
			}
		});
	}

	/**
	 * Convert the given string to an Item by using the configured converter.
	 *
	 * @param text The string that the converter knows how to convert to an item
	 */
	public void addItem(String text) {
		StringConverter<E> c = getConverter();
		if (c == null)
			throw new IllegalArgumentException("You must define a converter before you can add items as Strings");

		E item = c.fromString(text);

		if (item != null)
			getItems().add(item);
	}

	protected Skin<?> createDefaultSkin() {
// Path: src/main/java/tornadofx/control/skin/MultiSelectSkin.java
// public class MultiSelectSkin<E> extends SkinBase<MultiSelect<E>> {
// 
// 	public MultiSelectSkin(MultiSelect<E> control) {
// 		super(control);
// 	}
// 
// 	private double getPrefRowHeight() {
// 		double editorHeight = getSkinnable().getEditor().prefHeight(-1);
// 		if (getChildren().isEmpty())
// 			return editorHeight;
// 		else
// 			return Math.max(editorHeight, getChildren().get(0).prefHeight(-1));
// 	}
// 
// 	/**
// 	 * Compute pref width by placing equal amount of childen on each line, with a line height equal to the editors preferred
// 	 * height plus the vgap. This will not be correct in every case, depending on the difference in the other childrens
// 	 * preferred width, but it seems to be adequate.
// 	 */
// 	protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		MultiSelect<E> control = getSkinnable();
// 
// 		double hgap = control.getHgap().doubleValue();
// 		double vgap = control.getVgap().doubleValue();
// 		double prefRowHeight = getPrefRowHeight();
// 
// 		int childCount = getChildren().size();
// 		int rows = height <= 0 ? 1 : (int) Math.max(1, Math.floor((prefRowHeight + vgap) / height));
// 		int perRow = (int) Math.ceil(childCount / rows);
// 
// 		double widestRow = 0;
// 		int childPos = 0;
// 		for (int rowCount = 0; rowCount < rows; rowCount++) {
// 			double rowWidth = 0;
// 			double childPosInRow = 0;
// 
// 			while (childPosInRow < perRow && childPos < childCount) {
// 				Node child = getChildren().get(childPos);
// 				rowWidth += child.prefWidth(prefRowHeight) + hgap;
// 				childPos++;
// 				childPosInRow++;
// 			}
// 
// 			if (rowWidth > widestRow)
// 				widestRow = rowWidth;
// 		}
// 
// 		return widestRow + leftInset + rightInset - hgap;
// 	}
// 
// 	protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		return computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
// 	}
// 
// 	protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
// 		MultiSelect<E> control = getSkinnable();
// 
// 		double usedLineWidth = 0;
// 		double hgap = control.getHgap().doubleValue();
// 		double vgap = control.getVgap().doubleValue();
// 		double prefHeight = getPrefRowHeight();
// 
// 		double y = prefHeight;
// 		if (width == -1 && control.getWidth() > 0)
// 			width = control.getWidth();
// 
// 		for (Node node : getChildren()) {
// 			double prefWidth = node.prefWidth(prefHeight);
// 			if (width > 0 && usedLineWidth + prefWidth > width && usedLineWidth > 0) {
// 				usedLineWidth = 0;
// 				y += prefHeight + vgap;
// 			}
// 			usedLineWidth += prefWidth + hgap;
// 		}
// 
// 		return y;
// 	}
// 
// 	protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
// 		double usedLineWidth = 0;
// 		double hgap = getSkinnable().getHgap().doubleValue();
// 		double vgap = getSkinnable().getVgap().doubleValue();
// 		double prefHeight = getPrefRowHeight();
// 
// 		for (Node node : getChildren()) {
// 			double prefWidth = node.prefWidth(prefHeight);
// 			if (usedLineWidth + prefWidth > contentWidth && usedLineWidth > 0) {
// 				usedLineWidth = 0;
// 				contentY += prefHeight + vgap;
// 			}
// 			double x = usedLineWidth + contentX;
// 			node.resizeRelocate(x, contentY, prefWidth, prefHeight);
// 			usedLineWidth += prefWidth + hgap;
// 		}
// 	}
// 
// }


// Path: src/main/java/tornadofx/control/MultiSelect.java
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableProperty;
import javafx.css.StyleablePropertyFactory;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import javafx.util.StringConverter;
import tornadofx.control.skin.MultiSelectSkin;
import java.util.List;
import java.util.function.BiFunction;

					getChildren().remove(c.getFrom(), c.getTo() + 1);

				if (c.wasAdded()) {
					for (int i = 0; i < c.getAddedSize(); i++) {
						E item = c.getAddedSubList().get(i);
						Node cell = getCellFactory().apply(this, item);
						getChildren().add(i + c.getFrom(), cell);
					}
				}
			}
		});
	}

	/**
	 * Convert the given string to an Item by using the configured converter.
	 *
	 * @param text The string that the converter knows how to convert to an item
	 */
	public void addItem(String text) {
		StringConverter<E> c = getConverter();
		if (c == null)
			throw new IllegalArgumentException("You must define a converter before you can add items as Strings");

		E item = c.fromString(text);

		if (item != null)
			getItems().add(item);
	}

	protected Skin<?> createDefaultSkin() {
		return new MultiSelectSkin<>(this);