/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.kernel.geos; import java.util.ArrayList; import java.util.Iterator; import java.util.TreeSet; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.euclidian.EuclidianViewInterfaceCommon; import org.geogebra.common.euclidian.EuclidianViewInterfaceSlim; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.arithmetic.BooleanValue; import org.geogebra.common.kernel.arithmetic.MyBoolean; import org.geogebra.common.kernel.arithmetic.MyDouble; import org.geogebra.common.kernel.arithmetic.ValidExpression; import org.geogebra.common.kernel.arithmetic.ValueType; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.plugin.GeoClass; import org.geogebra.common.util.StringUtil; /** * * @author Markus */ public class GeoBoolean extends GeoElement implements BooleanValue, GeoNumberValue, AbsoluteScreenLocateable, HasExtendedAV { private boolean value = false; private boolean isDefined = true; private boolean checkboxFixed; private ArrayList<GeoElement> condListenersShowObject; /** * Creates new boolean * * @param c * construction */ public GeoBoolean(Construction c) { super(c); checkboxFixed = true; setEuclidianVisible(false); } /** * Creates new boolean * * @param cons * construction * @param value * value */ public GeoBoolean(Construction cons, boolean value) { this(cons); this.value = value; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_SHOW_HIDE_CHECKBOX; } @Override public GeoClass getGeoClassType() { return GeoClass.BOOLEAN; } /** * Changes value of this boolean * * @param val * new value */ public void setValue(boolean val) { setDefinition(null); value = val; } @Override final public boolean getBoolean() { return value; } @Override final public MyBoolean getMyBoolean() { return new MyBoolean(kernel, value); } @Override public GeoBoolean copy() { GeoBoolean ret = new GeoBoolean(cons); ret.setValue(value); return ret; } /** * Registers geo as a listener for updates of this boolean object. If this * object is updated it calls geo.updateConditions() * * @param geo * geo which should use this boolean as condition to show */ public void registerConditionListener(GeoElement geo) { if (condListenersShowObject == null) { condListenersShowObject = new ArrayList<GeoElement>(); } condListenersShowObject.add(geo); } /** * Unregisters geo as a listener for updates of this boolean object. * * @param geo * geo which uses this boolean as condition to show */ public void unregisterConditionListener(GeoElement geo) { if (condListenersShowObject != null) { condListenersShowObject.remove(geo); } } /** * Calls super.update() and update() for all registered condition listener * geos. */ @Override public void update(boolean drag) { super.update(drag); // update all registered locatables (they have this point as start // point) if (condListenersShowObject != null) { for (int i = 0; i < condListenersShowObject.size(); i++) { GeoElement geo = condListenersShowObject.get(i); kernel.notifyUpdate(geo); } } } /** * Tells conidition listeners that their condition is removed and calls * super.remove() */ @Override public void doRemove() { if (condListenersShowObject != null) { // copy conditionListeners into array Object[] geos = condListenersShowObject.toArray(); condListenersShowObject.clear(); // tell all condition listeners for (int i = 0; i < geos.length; i++) { GeoElement geo = (GeoElement) geos[i]; geo.removeCondition(this); kernel.notifyUpdate(geo); } } if (kernel.hasExercise()) { kernel.getExercise().notifyUpdate(); } super.doRemove(); } @Override public boolean showInEuclidianView() { return isIndependent() && isSimple(); } @Override public final boolean showInAlgebraView() { return true; } @Override public boolean isFixable() { // visible checkbox should not be fixable return isIndependent() && !isSetEuclidianVisible() && this.condShowObject == null && !isDefaultGeo(); } @Override public void set(GeoElementND geo) { if (geo.isGeoNumeric()) { // eg SetValue[checkbox, 0] // 1 = true // 0 = false setValue(Kernel.isZero(((GeoNumeric) geo).getDouble() - 1)); isDefined = true; } else { GeoBoolean b = (GeoBoolean) geo; setValue(b.value); isDefined = b.isDefined; } } @Override /** * Changes value to false. See also GeoBoolean.setUndefinedProverOnly() */ final public void setUndefined() { // don't change this, needed for compatibility // eg SetValue[a,?] sets it to false value = false; } /** * Set the undefined flag. Normal algos should use setUndefined which * changes value to false. */ final public void setUndefinedProverOnly() { // Needed for prover's yes/no/undefined trichotomy isDefined = false; } /** * Changes the defined flag of this boolean */ final public void setDefined() { isDefined = true; } @Override final public boolean isDefined() { return isDefined; } @Override final public String toValueString(StringTemplate tpl) { return value ? "true" : "false"; } @Override final public String toString(StringTemplate tpl) { StringBuilder sbToString = new StringBuilder(); sbToString.setLength(0); sbToString.append(label); sbToString.append(" = "); sbToString.append(toValueString(tpl)); return sbToString.toString(); } /** * returns all class-specific xml tags for saveXML */ @Override protected void getXMLtags(StringBuilder sb) { sb.append("\t<value val=\""); sb.append(value); sb.append("\"/>\n"); getXMLvisualTags(sb, isIndependent()); getXMLfixedTag(sb); getAuxiliaryXML(sb); getBreakpointXML(sb); // checkbox fixed if (checkboxFixed) { sb.append("\t<checkbox fixed=\""); sb.append(checkboxFixed); sb.append("\"/>\n"); } getScriptTags(sb); } @Override public boolean isGeoBoolean() { return true; } @Override public double getRealWorldLocX() { return 0; } @Override public double getRealWorldLocY() { return 0; } @Override public boolean isAbsoluteScreenLocActive() { return true; } @Override public boolean isAbsoluteScreenLocateable() { return isIndependent(); } /** * @param x * screen x * @param y * screen y * @param forced * set location even for fixed checkbox */ public void setAbsoluteScreenLoc(int x, int y, boolean forced) { if (!forced && checkboxFixed) { return; } labelOffsetX = x; labelOffsetY = y; } @Override public void setAbsoluteScreenLoc(int x, int y) { setAbsoluteScreenLoc(x, y, false); } @Override public int getAbsoluteScreenLocX() { return labelOffsetX; } @Override public int getAbsoluteScreenLocY() { return labelOffsetY; } @Override public void setAbsoluteScreenLocActive(boolean flag) { // do nothing } @Override public void setRealWorldLoc(double x, double y) { // do nothing } /** * @return true for fixed checkboxes */ public final boolean isCheckboxFixed() { return checkboxFixed; } /** * @param checkboxFixed * true to fix checkbox */ public final void setCheckboxFixed(boolean checkboxFixed) { this.checkboxFixed = checkboxFixed; } // Michael Borcherds 2008-04-30 @Override final public boolean isEqual(GeoElementND geo) { // return false if it's a different type, otherwise check if (geo.isGeoBoolean()) { return value == ((GeoBoolean) geo).getBoolean(); } return false; } @Override public boolean isNumberValue() { return true; } /** * Returns 1 for true and 0 for false. */ @Override public double getDouble() { return value ? 1 : 0; } @Override public MyDouble getNumber() { return new MyDouble(kernel, getDouble()); } /** * Returns whether the value (e.g. equation) should be shown as part of the * label description */ @Override final public boolean isLabelValueShowable() { return false; } @Override public boolean canHaveClickScript() { return false; } @Override final public boolean isCasEvaluableObject() { return true; } @Override public void moveDependencies(GeoElement oldGeo) { if (oldGeo.isGeoBoolean() && ((GeoBoolean) oldGeo).condListenersShowObject != null) { condListenersShowObject = ((GeoBoolean) oldGeo).condListenersShowObject; for (GeoElement geo : condListenersShowObject) { geo.condShowObject = this; } ((GeoBoolean) oldGeo).condListenersShowObject = null; } } @Override public void setEuclidianVisible(boolean visible) { if (visible && labelOffsetX == 0 && labelOffsetY == 0 && isIndependent()) { initScreenLocation(); } super.setEuclidianVisible(visible); } private void initScreenLocation() { int count = countCheckboxes(); labelOffsetX = 5; EuclidianViewInterfaceSlim ev = kernel.getApplication() .getActiveEuclidianView(); if (ev != null) { labelOffsetY = ev.getSliderOffsetY() - 45 + 30 * count; } else { labelOffsetY = 5 + 30 * count; } // make sure checkbox is visible on screen labelOffsetY = labelOffsetY / 400 * 10 + labelOffsetY % 400; } private int countCheckboxes() { int count = 0; // get all number and angle sliders TreeSet<GeoElement> bools = cons.getGeoSetLabelOrder(GeoClass.BOOLEAN); if (bools != null) { Iterator<GeoElement> it = bools.iterator(); while (it.hasNext()) { GeoBoolean num = (GeoBoolean) it.next(); if (num.isIndependent() && num.isEuclidianVisible()) { count++; } } } return count; } @Override final public HitType getLastHitType() { return HitType.ON_FILLING; } private boolean showExtendedAV = true; @Override public boolean isShowingExtendedAV() { return showExtendedAV; } @Override public void setShowExtendedAV(boolean showExtendedAV) { this.showExtendedAV = showExtendedAV; } @Override public ValueType getValueType() { return ValueType.BOOLEAN; } @Override public ValidExpression toValidExpression() { return getMyBoolean(); } public int getTotalWidth(EuclidianViewInterfaceCommon ev) { return (int) (32 + StringUtil.getPrototype().estimateLength( getCaption(StringTemplate.defaultTemplate), ev.getApplication().getFontCanDisplay(label))); } public int getTotalHeight(EuclidianViewInterfaceCommon ev) { return 32; } }