package nl.utwente.viskell.ui;
import java.util.stream.Stream;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import nl.utwente.viskell.ui.components.Block;
/**
* A generic interface for block containers.
*/
public interface BlockContainer {
/** Gets the bounds to be used for testing what is inside this container, transformed into the coordinate space of its scene. */
Bounds containmentBoundsInScene();
/** Attach a block to this container */
void attachBlock(Block block);
/** Detach a block from this container */
void detachBlock(Block block);
/** @return a stream of all block attached to this container */
Stream<Block> getAttachedBlocks();
/** Check whether this container contains the specified block */
default boolean containsBlock(Block block) {
return this.getAttachedBlocks().anyMatch(a -> block.equals(a));
}
/** @return the container to which this container belongs, maybe return itself if it is the outermost container */
BlockContainer getParentContainer();
/**
* @return the ToplevelPane where this container is (indirectly) part of.
* @throws IllegalStateException
*/
default ToplevelPane getToplevel() {
BlockContainer cont = this;
while (cont.getParentContainer() != cont) {
cont = cont.getParentContainer();
}
if (cont instanceof ToplevelPane) {
return (ToplevelPane)cont;
}
throw new IllegalStateException("Manipulating container that is not in a ToplevelPane");
}
Node asNode();
/** @return Whether this container is (indirectly) contained with the other container. */
default boolean isContainedWithin(BlockContainer other) {
if (this == other) {
return true;
}
BlockContainer target = this;
while (target.getParentContainer() != target) {
target = target.getParentContainer();
if (target == other) {
return true;
}
}
return false;
}
/**
* Grows the bounds of this container to fit the given additional bounds.
* @param blockBounds of the Block that needs to fit in the container.
*/
void expandToFit(Bounds blockBounds);
/** Return the union of two Bounds, i.e. a Bound that contains both. */
static Bounds union(Bounds a, Bounds b) {
double left = Math.min(a.getMinX(), b.getMinX());
double right = Math.max(a.getMaxX(), b.getMaxX());
double top = Math.min(a.getMinY(), b.getMinY());
double bottom = Math.max(a.getMaxY(), b.getMaxY());
return new BoundingBox(left, top, right - left, bottom - top);
}
}