package org.geogebra.common.gui.dialog.options.model; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.geos.GeoAngle; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.main.App; public class SliderModel extends OptionsModel { public interface ISliderOptionsListener extends PropertyListener { void setMinText(final String text); void setMaxText(final String text); void setWidthText(final String text); void setWidthUnitText(final String text); void selectFixed(boolean value); void selectRandom(boolean value); void setRandomVisible(boolean value); void setSliderDirection(int i); @Override Object updatePanel(Object[] geos2); } public final static int TEXT_FIELD_FRACTION_DIGITS = 8; private ISliderOptionsListener listener; private Kernel kernel; private boolean widthUnit; private boolean includeRandom; public SliderModel(App app, ISliderOptionsListener listener) { super(app); kernel = app.getKernel(); this.listener = listener; includeRandom = false; } @Override protected boolean isValidAt(int index) { GeoElement geo = getGeoAt(index); if (!(geo.isIndependent() && geo.isGeoNumeric())) { return false; } return true; } protected GeoNumeric getNumericAt(int index) { return (GeoNumeric) getObjectAt(index); } @Override public void updateProperties() { // check if properties have same values GeoNumeric temp, num0 = getNumericAt(0); boolean equalMax = true; boolean equalMin = true; boolean equalWidth = true; boolean equalSliderFixed = true; boolean random = true; boolean equalSliderHorizontal = true; boolean onlyAngles = true; boolean equalPinned = true; for (int i = 0; i < getGeosLength(); i++) { temp = getNumericAt(i); // we don't check isIntervalMinActive, because we want to display // the interval even if it's empty if (num0.getIntervalMinObject() == null || temp.getIntervalMinObject() == null || !Kernel.isEqual(num0.getIntervalMin(), temp.getIntervalMin())) { equalMin = false; } if (num0.getIntervalMaxObject() == null || temp.getIntervalMaxObject() == null || !Kernel.isEqual(num0.getIntervalMax(), temp.getIntervalMax())) { equalMax = false; } if (!Kernel.isEqual(num0.getSliderWidth(), temp.getSliderWidth())) { equalWidth = false; } if (num0.isSliderFixed() != temp.isSliderFixed()) { equalSliderFixed = false; } if (num0.isRandom() != temp.isRandom()) { random = false; } if (num0.isSliderHorizontal() != temp.isSliderHorizontal()) { equalSliderHorizontal = false; } if (num0.isPinned() != temp.isPinned()) { equalPinned = false; } if (!(temp instanceof GeoAngle)) { onlyAngles = false; } } StringTemplate highPrecision = StringTemplate.printDecimals( StringType.GEOGEBRA, TEXT_FIELD_FRACTION_DIGITS, false); if (equalMin) { GeoElement min0 = GeoElement.as(num0.getIntervalMinObject()); if (onlyAngles && (min0 == null || (!min0.isLabelSet() && min0.isIndependent()))) { listener.setMinText(kernel .formatAngle(num0.getIntervalMin(), highPrecision, true) .toString()); } else { listener.setMinText( num0.getIntervalMinObject().getLabel(highPrecision)); } } else { listener.setMinText(""); } if (equalMax) { GeoElement max0 = GeoElement.as(num0.getIntervalMaxObject()); if (onlyAngles && (max0 == null || (!max0.isLabelSet() && max0.isIndependent()))) { listener.setMaxText(kernel .formatAngle(num0.getIntervalMax(), highPrecision, true) .toString()); } else { listener.setMaxText( num0.getIntervalMaxObject().getLabel(highPrecision)); } } else { listener.setMaxText(""); } widthUnit = false; if (equalWidth && equalPinned) { listener.setWidthText( kernel.format(num0.getSliderWidth(), highPrecision)); if (num0.isPinned()) { widthUnit = true; } } else { listener.setMaxText(""); } setLabelForWidthUnit(); if (equalSliderFixed) { listener.selectFixed(num0.isSliderFixed()); } if (random) { listener.selectRandom(num0.isRandom()); } listener.setRandomVisible(isIncludeRandom()); if (equalSliderHorizontal) { // TODO why doesn't this work when you create a slider listener.setSliderDirection(num0.isSliderHorizontal() ? 0 : 1); } } public void setLabelForWidthUnit() { listener.setWidthUnitText( widthUnit ? app.getLocalization().getMenu("Pixels.short") : ""); } public void applyFixed(boolean value) { for (int i = 0; i < getGeosLength(); i++) { GeoNumeric num = getNumericAt(i); num.setSliderFixed(value); num.updateRepaint(); } storeUndoInfo(); } public void applyRandom(boolean value) { for (int i = 0; i < getGeosLength(); i++) { GeoNumeric num = getNumericAt(i); num.setRandom(value); num.updateRepaint(); } storeUndoInfo(); } public void applyDirection(int value) { boolean isHorizontal = value == 0; for (int i = 0; i < getGeosLength(); i++) { GeoNumeric num = getNumericAt(i); num.setSliderHorizontal(isHorizontal); num.updateRepaint(); } storeUndoInfo(); } private void applyExtrema(NumberValue value, boolean isMinimum) { for (int i = 0; i < getGeosLength(); i++) { GeoNumeric num = getNumericAt(i); boolean dependsOnListener = false; GeoElement geoValue = value.toGeoElement(num.getConstruction()); if (num.getMinMaxListeners() != null) { for (GeoNumeric numListener : num.getMinMaxListeners()) { if (geoValue.isChildOrEqual(numListener)) { dependsOnListener = true; } } } if (dependsOnListener || geoValue.isChildOrEqual(num)) { app.showError( app.getLocalization().getError("CircularDefinition")); } else { if (isMinimum) { num.setIntervalMin(value); } else { num.setIntervalMax(value); } } num.updateRepaint(); } storeUndoInfo(); } public void applyMin(NumberValue value) { applyExtrema(value, true); } public void applyMax(NumberValue value) { applyExtrema(value, false); } public void applyWidth(double value) { for (int i = 0; i < getGeosLength(); i++) { GeoNumeric num = getNumericAt(i); num.setSliderWidth(value); num.updateRepaint(); } storeUndoInfo(); } public boolean isIncludeRandom() { return includeRandom; } public void setIncludeRandom(boolean includeRandom) { this.includeRandom = includeRandom; } @Override public PropertyListener getListener() { return listener; } }