All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dua3.utility.fx.controls.PinBoard Maven / Gradle / Ivy

There is a newer version: 15.0.2
Show newest version
/*
 * Copyright (c) 2022. Axel Howind ([email protected])
 * This package is distributed under the Artistic License 2.0.
 */

package com.dua3.utility.fx.controls;

import com.dua3.utility.fx.FxUtil;
import com.dua3.utility.fx.PlatformHelper;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Dimension2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.control.Control;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.function.Supplier;


/**
 * A JavaFX component where items can be pinned at a position.
 */
@SuppressWarnings("MagicCharacter")
public class PinBoard extends Control {

    final ObservableList items = FXCollections.observableArrayList();
    private final ObjectProperty areaProperty = new SimpleObjectProperty<>(new Rectangle2D(0, 0, 0, 0));

    /**
     * Default constructor.
     */
    public PinBoard() {
    }

    /**
     * Sets the horizontal scrollbar policy of the PinBoardSkin's ScrollPane.
     *
     * @param policy the scrollbar policy to set
     */
    public void setHbarPolicy(ScrollPane.ScrollBarPolicy policy) {
        if (getSkin() instanceof PinBoardSkin skin) {
            skin.setHbarPolicy(policy);
        }
    }

    /**
     * Sets the vertical scrollbar policy of the PinBoardSkin's ScrollPane.
     *
     * @param policy the ScrollBarPolicy to set
     */
    public void setVbarPolicy(ScrollPane.ScrollBarPolicy policy) {
        if (getSkin() instanceof PinBoardSkin skin) {
            skin.setVbarPolicy(policy);
        }
    }

    /**
     * Clears the PinBoard by removing all items and resetting the area property.
     * This method must be called from the JavaFX Application Thread.
     */
    public void clear() {
        PlatformHelper.checkApplicationThread();
        items.clear();
        areaProperty.set(new Rectangle2D(0, 0, 0, 0));
    }

    /**
     * Refreshes the PinBoard skin.
     * 

* This method is used to refresh the visual representation of the PinBoard. It checks if the skin associated * with the PinBoard is an instance of PinBoardSkin and then calls the {@link PinBoardSkin#refresh()} method * to update the nodes displayed on the board. *

*/ public void refresh() { if (getSkin() instanceof PinBoardSkin skin) { skin.refresh(); } } /** * Disposes the PinBoardSkin instance. * Stops the refresher and disposes the superclass. */ public void dispose() { if (getSkin() instanceof PinBoardSkin skin) { skin.dispose(); } } @Override protected Skin createDefaultSkin() { return new PinBoardSkin(this); } /** * Returns the read-only property that represents the area of the PinBoard. * * @return The read-only area property of type Rectangle2D. */ public ReadOnlyObjectProperty areaProperty() { return areaProperty; } /** * Returns an unmodifiable observable list of items. * * @return An unmodifiable observable list of items. */ public ObservableList getItems() { return FXCollections.unmodifiableObservableList(items); } /** * Retrieves the current scroll position of the PinBoard. * * @return a Pair containing the horizontal and vertical scroll positions */ public ScrollPosition getScrollPosition() { if (getSkin() instanceof PinBoardSkin skin) { return skin.getScrollPosition(); } else { return ScrollPosition.ORIGIN; } } /** * Sets the scroll position of the PinBoardSkin's ScrollPane. * * @param hValue the horizontal scroll value to set * @param vValue the vertical scroll value to set */ public void setScrollPosition(double hValue, double vValue) { if (getSkin() instanceof PinBoardSkin skin) { skin.setScrollPosition(hValue, vValue); } } /** * Sets the scroll position of the PinBoardSkin's ScrollPane. * * @param scrollPosition a Pair containing the horizontal and vertical scroll positions */ public void setScrollPosition(ScrollPosition scrollPosition) { if (getSkin() instanceof PinBoardSkin skin) { skin.setScrollPosition(scrollPosition); } } /** * Scrolls the PinBoard to the specified position within an item. * * @param pos the position within an item to scroll to */ public void scrollTo(PositionInItem pos) { if (getSkin() instanceof PinBoardSkin skin) { skin.scrollTo(pos); } } /** * Get Item at point. * * @param x x-coordinate (relative to viewport) * @param y y-coordinate (relative to viewport) * @return Optional containing the item at (x,y) */ public Optional getItemAt(double x, double y) { return getPositionInItem(x, y).map(PositionInItem::item); } /** * Get Item at point and coordinates transformed to item coordinates. * * @param x x-coordinate (relative to viewport) * @param y y-coordinate (relative to viewport) * @return Optional containing the item and the transformed coordinates */ public Optional getPositionInItem(double x, double y) { if (getSkin() instanceof PinBoardSkin skin) { return skin.getPositionInItem(x, y); } else { return Optional.empty(); } } /** * Add item at the bottom, centered horizontally. * * @param name item name * @param nodeSupplier supplier (factory) for item node * @param dimension item dimension */ public void pinBottom(String name, Supplier nodeSupplier, Dimension2D dimension) { Rectangle2D boardArea = getArea(); double xCenter = (boardArea.getMaxX() + boardArea.getMinX()) / 2.0; double y = boardArea.getMaxY(); Rectangle2D area = new Rectangle2D(xCenter - dimension.getWidth() / 2, y, dimension.getWidth(), dimension.getHeight()); pin(new Item(name, area, nodeSupplier)); } /** * Returns the area of the PinBoard. * * @return The Rectangle2D representing the area of the PinBoard. */ public Rectangle2D getArea() { return areaProperty.get(); } /** * Pins the given item or collection of items to the PinBoard. * * @param item The item to be pinned. Can be a single item or a collection of items to be pinned together. */ public void pin(Item item) { pin(Collections.singleton(item)); } /** * Pins the given collection of items to the PinBoard. * * @param itemsToPin The collection of items to be pinned. */ public void pin(Collection itemsToPin) { PlatformHelper.checkApplicationThread(); if (itemsToPin.isEmpty()) { return; } items.addAll(itemsToPin); itemsToPin.stream() .map(Item::area) .reduce(FxUtil::union) .map(r -> FxUtil.union(getArea(), r)) .ifPresent(r -> { if (!r.equals(getArea())) { areaProperty.set(r); } }); } @Override public String toString() { return "PinBoard{" + "area=" + areaProperty.get() + ", items=" + items + '}'; } /** * The Item class represents an item on a PinBoard. It contains information about the item's name, area, * and a supplier that can be used to build the item's Node representation. * * @param name The name of the item. * @param area The area occupied by the item on the PinBoard. * @param nodeBuilder A supplier that can be used to build the Node representation of the item. */ public record Item(String name, Rectangle2D area, Supplier nodeBuilder) {} /** * The PositionInItem class represents the position within an item on a PinBoard. * It contains information about the item, as well as the x and y coordinates within the item. * This class is used for scrolling to a specific position within an item and retrieving the item at a given point. * * @param item The item within which the position is located. * @param x The x-coordinate within the item. * @param y The y-coordinate within the item. */ public record PositionInItem(Item item, double x, double y) {} }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy