001package conexp.fx.gui.properties;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2023 Francesco Kriegel
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import conexp.fx.core.collections.IntPair;
026import javafx.beans.binding.ObjectBinding;
027import javafx.beans.value.ChangeListener;
028import javafx.beans.value.ObservableValue;
029
030public class BoundedIntPairProperty extends SimpleIntPairProperty {
031
032  private final ObjectBinding<IntPair> lowerBound;
033  private final ObjectBinding<IntPair> upperBound;
034
035  public BoundedIntPairProperty(
036      IntPair initialValue,
037      ObjectBinding<IntPair> lowerBound,
038      ObjectBinding<IntPair> upperBound) throws RuntimeException {
039    super(initialValue);
040    if (lowerBound.get().x() > upperBound.get().x() || lowerBound.get().y() > upperBound.get().y()
041        || initialValue.x() < lowerBound.get().x() || initialValue.x() > upperBound.get().x()
042        || initialValue.y() < lowerBound.get().y() || initialValue.y() > upperBound.get().y())
043      throw new RuntimeException("lower bound is not smaller than upper bound, or initial value is not between them!");
044    this.lowerBound = lowerBound;
045    this.upperBound = upperBound;
046    lowerBound.addListener(new ChangeListener<IntPair>() {
047
048      @Override
049      public void changed(ObservableValue<? extends IntPair> observable, IntPair oldValue, IntPair newValue) {
050        if (getValue().x() < newValue.x() || getValue().y() < newValue.y())
051          setValue(truncate(getValue()));
052      }
053    });
054    upperBound.addListener(new ChangeListener<IntPair>() {
055
056      @Override
057      public void changed(ObservableValue<? extends IntPair> observable, IntPair oldValue, IntPair newValue) {
058        if (getValue().x() > newValue.x() || getValue().y() > newValue.y())
059          setValue(truncate(getValue()));
060      }
061    });
062  }
063
064  private final IntPair truncate(final IntPair value) {
065    value.setX(Math.min(Math.max(value.x(), lowerBound.get().x()), upperBound.get().x()));
066    value.setY(Math.min(Math.max(value.y(), lowerBound.get().y()), upperBound.get().y()));
067    return value;
068  }
069
070  @Override
071  public void set(int x, int y) {
072    set(truncate(IntPair.valueOf(x, y)));
073  }
074
075  @Override
076  public void set(IntPair v) {
077    super.set(truncate(v));
078  }
079
080  @Override
081  public void setValue(IntPair v) {
082    set(truncate(v));
083  }
084}