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

io.github.palexdev.mfxcomponents.layout.LayoutStrategy Maven / Gradle / Ivy

There is a newer version: 11.26.0
Show newest version
/*
 * Copyright (C) 2023 Parisi Alessandro - [email protected]
 * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX)
 *
 * MaterialFX is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 3 of the License,
 * or (at your option) any later version.
 *
 * MaterialFX is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with MaterialFX. If not, see .
 */

package io.github.palexdev.mfxcomponents.layout;

import io.github.palexdev.mfxcomponents.controls.base.MFXSkinBase;
import io.github.palexdev.mfxcore.base.TriFunction;
import io.github.palexdev.mfxcore.builders.InsetsBuilder;
import javafx.geometry.Insets;
import javafx.scene.control.Skin;

import java.util.Objects;
import java.util.function.Function;

/**
 * A {@code LayoutStrategy} defines a series of {@link Function}s that are responsible for computing:
 * 

1) The minimum width *

2) The minimum height *

3) The preferred width *

4) The preferred height *

5) The maximum width *

6) The maximum height *

* ...of a component that implements {@link MFXResizable}. *

* An internal class, {@link Defaults}, offers a series of default layout functions that replicate the JavaFX's * algorithm. *

* A good usage of this is to start from the defaults and then extend them using the {@link Function#andThen(Function)} * feature. *

* When creating a new {@code LayoutStrategy} object through no-arg constructor or {@link #defaultStrategy()}, the six * functions are set to the one in {@link Defaults} (JavaFX algorithm). *

*

* In general the JavaFX's layout algorithm works like this: *

- Given the min, pref and max widths/heights for a Node *

1) Extracts the maximum between pref and min *

2) Extracts the maximum between min and max *

3) Returns the minimum between the two computed values */ public class LayoutStrategy { //================================================================================ // Properties //================================================================================ private Function minWidthFunction = Defaults.DEF_MIN_WIDTH_FUNCTION; private Function minHeightFunction = Defaults.DEF_MIN_HEIGHT_FUNCTION; private Function prefWidthFunction = Defaults.DEF_PREF_WIDTH_FUNCTION; private Function prefHeightFunction = Defaults.DEF_PREF_HEIGHT_FUNCTION; private Function maxWidthFunction = Defaults.DEF_MAX_WIDTH_FUNCTION; private Function maxHeightFunction = Defaults.DEF_MAX_HEIGHT_FUNCTION; //================================================================================ // Static Methods //================================================================================ /** * @return a new {@code LayoutStrategy} instance that uses JavaFX's algorithm for all sizes */ public static LayoutStrategy defaultStrategy() { return new LayoutStrategy(); } //================================================================================ // Methods //================================================================================ /** * Computes the minimum width for the specified {@link MFXResizable} by invoking the set {@link #getMinWidthFunction()}. * * @return the computed width or 0.0 if the function is null */ public double computeMinWidth(MFXResizable resizable) { return minWidthFunction != null ? minWidthFunction.apply(resizable) : 0.0; } /** * Computes the minimum height for the specified {@link MFXResizable} by invoking the set {@link #getMinHeightFunction()}. * * @return the computed height or 0.0 if the function is null */ public double computeMinHeight(MFXResizable resizable) { return minHeightFunction != null ? minHeightFunction.apply(resizable) : 0.0; } /** * Computes the preferred width for the specified {@link MFXResizable} by invoking the set {@link #getPrefWidthFunction()}. * * @return the computed width or 0.0 if the function is null */ public double computePrefWidth(MFXResizable resizable) { return prefWidthFunction != null ? prefWidthFunction.apply(resizable) : 0.0; } /** * Computes the preferred height for the specified {@link MFXResizable} by invoking the set {@link #getPrefHeightFunction()}. * * @return the computed height or 0.0 if the function is null */ public double computePrefHeight(MFXResizable resizable) { return prefHeightFunction != null ? prefHeightFunction.apply(resizable) : 0.0; } /** * Computes the maximum width for the specified {@link MFXResizable} by invoking the set {@link #getMaxWidthFunction()}. * * @return the computed width or 0.0 if the function is null */ public double computeMaxWidth(MFXResizable resizable) { return maxWidthFunction != null ? maxWidthFunction.apply(resizable) : 0.0; } /** * Computes the maximum height for the specified {@link MFXResizable} by invoking the set {@link #getMaxHeightFunction()}. * * @return the computed height or 0.0 if the function is null */ public double computeMaxHeight(MFXResizable resizable) { return maxHeightFunction != null ? maxHeightFunction.apply(resizable) : 0.0; } /** * Fluent API to set this {@code LayoutStrategy} on the given {@link MFXResizable}. * * @see MFXResizable#setLayoutStrategy(LayoutStrategy) */ public LayoutStrategy setOn(MFXResizable resizable) { resizable.setLayoutStrategy(this); return this; } //================================================================================ // Overridden Methods //================================================================================ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LayoutStrategy that = (LayoutStrategy) o; return Objects.equals(getMinWidthFunction(), that.getMinWidthFunction()) && Objects.equals(getMinHeightFunction(), that.getMinHeightFunction()) && Objects.equals(getPrefWidthFunction(), that.getPrefWidthFunction()) && Objects.equals(getPrefHeightFunction(), that.getPrefHeightFunction()) && Objects.equals(getMaxWidthFunction(), that.getMaxWidthFunction()) && Objects.equals(getMaxHeightFunction(), that.getMaxHeightFunction()); } @Override public int hashCode() { return Objects.hash( getMinWidthFunction(), getMinHeightFunction(), getPrefWidthFunction(), getPrefHeightFunction(), getMaxWidthFunction(), getMaxHeightFunction() ); } //================================================================================ // Getters/Setters //================================================================================ public Function getMinWidthFunction() { return minWidthFunction; } public LayoutStrategy setMinWidthFunction(Function minWidthFunction) { this.minWidthFunction = minWidthFunction; return this; } public Function getMinHeightFunction() { return minHeightFunction; } public LayoutStrategy setMinHeightFunction(Function minHeightFunction) { this.minHeightFunction = minHeightFunction; return this; } public Function getPrefWidthFunction() { return prefWidthFunction; } public LayoutStrategy setPrefWidthFunction(Function prefWidthFunction) { this.prefWidthFunction = prefWidthFunction; return this; } public Function getPrefHeightFunction() { return prefHeightFunction; } public LayoutStrategy setPrefHeightFunction(Function prefHeightFunction) { this.prefHeightFunction = prefHeightFunction; return this; } public Function getMaxWidthFunction() { return maxWidthFunction; } public LayoutStrategy setMaxWidthFunction(Function maxWidthFunction) { this.maxWidthFunction = maxWidthFunction; return this; } public Function getMaxHeightFunction() { return maxHeightFunction; } public LayoutStrategy setMaxHeightFunction(Function maxHeightFunction) { this.maxHeightFunction = maxHeightFunction; return this; } public static class Defaults { public static final Function DEF_MIN_WIDTH_FUNCTION; public static final Function DEF_MIN_HEIGHT_FUNCTION; public static final Function DEF_PREF_WIDTH_FUNCTION; public static final Function DEF_PREF_HEIGHT_FUNCTION; public static final Function DEF_MAX_WIDTH_FUNCTION; public static final Function DEF_MAX_HEIGHT_FUNCTION; static { DEF_MIN_WIDTH_FUNCTION = createFunction( MFXResizable::getHeight, (s, h, i) -> s.computeMinWidth(h, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); DEF_MIN_HEIGHT_FUNCTION = createFunction( MFXResizable::getWidth, (s, w, i) -> s.computeMinHeight(w, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); DEF_PREF_WIDTH_FUNCTION = createFunction( MFXResizable::getHeight, (s, h, i) -> s.computePrefWidth(h, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); DEF_PREF_HEIGHT_FUNCTION = createFunction( MFXResizable::getWidth, (s, w, i) -> s.computePrefHeight(w, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); DEF_MAX_WIDTH_FUNCTION = createFunction( MFXResizable::getHeight, (s, h, i) -> s.computeMaxWidth(h, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); DEF_MAX_HEIGHT_FUNCTION = createFunction( MFXResizable::getWidth, (s, w, i) -> s.computeMaxHeight(w, i.getTop(), i.getRight(), i.getBottom(), i.getLeft()) ); } private static Function createFunction( Function otherSize, TriFunction, Double, Insets, Double> fn) { return c -> { Skin skin = c.getSkin(); if (!(skin instanceof MFXSkinBase)) return 0.0; Double oSize = otherSize.apply(c); return fn.apply(((MFXSkinBase) skin), oSize, getSnappedInsets(c)); }; } private static Insets getSnappedInsets(MFXResizable res) { return InsetsBuilder.of( res.snappedTopInset(), res.snappedRightInset(), res.snappedBottomInset(), res.snappedLeftInset() ); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy