package org.geogebra.common.gui;
import java.util.ArrayList;
import org.geogebra.common.awt.GPoint;
import org.geogebra.common.euclidian.Drawable;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.euclidian.EuclidianStyleBarStatic;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.euclidian.Hits;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.geos.AbsoluteScreenLocateable;
import org.geogebra.common.kernel.geos.GProperty;
import org.geogebra.common.kernel.geos.GeoBoolean;
import org.geogebra.common.kernel.geos.GeoConic;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoSegment;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.kernel.geos.GeoVector;
import org.geogebra.common.kernel.geos.Traceable;
import org.geogebra.common.kernel.implicit.GeoImplicit;
import org.geogebra.common.kernel.kernelND.CoordStyle;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.OptionType;
import org.geogebra.common.main.SpreadsheetTraceManager;
/**
* @author gabor
*
* Superclass for ContextMenuGeoElements in Web and Desktop
*
*/
public abstract class ContextMenuGeoElement {
protected static final double[] zoomFactors = { 4.0, 2.0, 1.5, 1.25,
1.0 / 1.25, 1.0 / 1.5, 0.5, 0.25 };
protected static final double[] axesRatios = { 1.0 / 1000.0, 1.0 / 500.0,
1.0 / 200.0, 1.0 / 100.0, 1.0 / 50.0, 1.0 / 20.0, 1.0 / 10.0,
1.0 / 5.0, 1.0 / 2.0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
/** selected elements */
private ArrayList<GeoElement> geos;
/** current element */
private String geoLabel;
/** application */
public App app;
protected boolean justOneGeo = false;
public ContextMenuGeoElement(App app) {
this.app = app;
}
/**
*
* @param geo
* geo
* @return description
*/
protected String getDescription(GeoElement geo, boolean addHTMLtag) {
String title = geo.getLongDescriptionHTML(false, addHTMLtag);
if (title.length() > 80) {
title = geo.getNameDescriptionHTML(false, addHTMLtag);
}
return title;
}
public void cartesianCoordsCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof CoordStyle) {
CoordStyle point1 = (CoordStyle) geo1;
point1.setMode(Kernel.COORD_CARTESIAN);
geo1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void polarCoorsCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof CoordStyle) {
CoordStyle point1 = (CoordStyle) geo1;
point1.setMode(Kernel.COORD_POLAR);
geo1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void cartesianCoords3dCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof CoordStyle) {
CoordStyle point1 = (CoordStyle) geo1;
point1.setMode(Kernel.COORD_CARTESIAN_3D);
geo1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void sphericalCoordsCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof CoordStyle) {
CoordStyle point1 = (CoordStyle) geo1;
point1.setMode(Kernel.COORD_SPHERICAL);
geo1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void equationImplicitEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoLine && !(geo1 instanceof GeoSegment)) {
GeoLine line1 = (GeoLine) geo1;
line1.setMode(GeoLine.EQUATION_IMPLICIT);
line1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationExplicitEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoLine && !(geo1 instanceof GeoSegment)) {
GeoLine line1 = (GeoLine) geo1;
line1.setMode(GeoLine.EQUATION_EXPLICIT);
line1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationGeneralLineEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoLine && !(geo1 instanceof GeoSegment)) {
GeoLine line1 = (GeoLine) geo1;
line1.setMode(GeoLine.EQUATION_GENERAL);
line1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void parametricFormCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoLine && !(geo1 instanceof GeoSegment)) {
GeoLine line1 = (GeoLine) geo1;
line1.setMode(GeoLine.PARAMETRIC);
line1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void cartesianCoordsForVectorItemsCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoVector) {
GeoVector vector1 = (GeoVector) geo1;
vector1.setMode(Kernel.COORD_CARTESIAN);
vector1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void polarCoordsForVectorItemsCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof GeoVector) {
GeoVector vector1 = (GeoVector) geo1;
vector1.setMode(Kernel.COORD_POLAR);
vector1.updateRepaint();
}
}
app.getKernel().getConstruction().getUndoManager().storeUndoInfo(true);
}
public void implicitConicEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.getClass() == GeoConic.class) {
GeoConic conic1 = (GeoConic) geo1;
conic1.setToImplicit();
conic1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationConicEqnCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.getClass() == GeoConic.class) {
GeoConic conic1 = (GeoConic) geo1;
conic1.setToSpecific();
conic1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationVertexEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.getClass() == GeoConic.class) {
GeoConic conic1 = (GeoConic) geo1;
conic1.setToVertexform();
conic1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationConicformEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.getClass() == GeoConic.class) {
GeoConic conic1 = (GeoConic) geo1;
conic1.setToConicform();
conic1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void equationExplicitConicEquationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.getClass() == GeoConic.class) {
GeoConic conic1 = (GeoConic) geo1;
conic1.setToExplicit();
conic1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void extendedFormCmd(final GeoImplicit inputElement) {
inputElement.setExtendedForm();
inputElement.updateRepaint();
app.storeUndoInfo();
}
public void deleteCmd(boolean isCut) {
ArrayList<GeoElement> geos2 = checkOneGeo();
// geo.remove();
for (int i = geos2.size() - 1; i >= 0; i--) {
// maybe we killed siblings -> geos2 list shrinks
if (i < geos2.size()) {
GeoElement geo1 = geos2.get(i);
// clear bounding box if geo if is there any
if (geo1.isShape()) {
Drawable d = (Drawable) app.getActiveEuclidianView()
.getDrawableFor(geo1);
if (d != null) {
d.getBoundingBox().resetBoundingBox();
}
}
if (isCut) {
if (geo1.getParentAlgorithm() != null) {
for (GeoElement ge : geo1.getParentAlgorithm().input) {
ge.removeOrSetUndefinedIfHasFixedDescendent();
}
}
}
geo1.removeOrSetUndefinedIfHasFixedDescendent();
}
}
app.storeUndoInfo();
}
public ArrayList<GeoElement> checkOneGeo() {
if (justOneGeo) {
ArrayList<GeoElement> ret = new ArrayList<GeoElement>();
ret.add(getGeo());
return ret;
}
return getGeos();
}
public void editCmd() {
app.getDialogManager().showTextDialog((GeoText) getGeo());
}
public void renameCmd() {
app.getDialogManager().showRenameDialog(getGeo(), true,
getGeo().getLabelSimple(), true);
}
public void fixObjectNumericCmd(final GeoNumeric num) {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isGeoNumeric()) {
((GeoNumeric) geo1).setSliderFixed(!num.isSliderFixed());
geo1.updateRepaint();
} else {
geo1.setFixed(!num.isSliderFixed());
}
}
app.storeUndoInfo();
}
public void fixObjectCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isGeoNumeric()) {
((GeoNumeric) geo1)
.setSliderFixed(!((GeoNumeric) geo1).isSliderFixed());
geo1.updateRepaint();
} else {
if (geo1.isFixable()) {
geo1.setFixed(!geo1.isLocked());
geo1.updateRepaint();
}
}
}
getGeo().updateVisualStyle(GProperty.COMBINED);
app.getKernel().notifyRepaint();
app.storeUndoInfo();
}
public void fixCheckboxCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoBoolean geo1 = (GeoBoolean) geos2.get(i);
geo1.setCheckboxFixed(!geo1.isCheckboxFixed());
}
app.storeUndoInfo();
}
public boolean isLabelShown() {
return isLabelShown(checkOneGeo());
}
public boolean isLabelShown(ArrayList<GeoElement> geos2) {
boolean show = true;
for (int i = geos2.size() - 1; i >= 0; i--) {
show = show && geos2.get(i).isLabelVisible();
}
return show;
}
public void showLabelCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
boolean show = isLabelShown(geos2);
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
geo1.setLabelVisible(!show);
geo1.updateRepaint();
}
app.storeUndoInfo();
}
public void showObjectCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
boolean newVisibility = !geos2.get(0).isSetEuclidianVisible();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
geo1.setEuclidianVisible(newVisibility);
// do not show bounding box if shape is not shown
if (!newVisibility && geo1.isShape()) {
Drawable d = (Drawable) app.getActiveEuclidianView()
.getDrawableFor(geo1);
if (d != null) {
d.getBoundingBox().resetBoundingBox();
}
}
geo1.updateRepaint();
}
app.storeUndoInfo();
}
public void showObjectAuxiliaryCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isAlgebraShowable()) {
geo1.setAuxiliaryObject(!geo1.isAuxiliaryObject());
geo1.updateRepaint();
}
}
app.storeUndoInfo();
}
public void openPropertiesDialogCmd() {
app.getDialogManager().showPropertiesDialog(OptionType.OBJECTS,
checkOneGeo());
}
public void inputFormCmd(final GeoImplicit inputElement) {
inputElement.setInputForm();
inputElement.updateRepaint();
app.storeUndoInfo();
}
public void traceCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
if (app.has(Feature.IMPROVE_CONTEXT_MENU)) { // if there is at least 1
// geo, which has no
// trace, all geo will
// have trace,
// otherwise, if all geo
// has trace, tracing
// will be set to false
boolean istracing = isTracing();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isTraceable()) {
((Traceable) geo1).setTrace(!istracing);
geo1.updateRepaint();
}
}
} else { // every geo's behaviour will be changed for the inverse
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isTraceable()) {
((Traceable) geo1).setTrace(!((Traceable) geo1).getTrace());
geo1.updateRepaint();
}
}
}
app.storeUndoInfo();
}
public boolean isTracing() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isTraceable()) {
if(!((Traceable) geo1).getTrace()){
return false;
}
}
}
return true;
}
public void animationCmd() {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1.isAnimatable()) {
geo1.setAnimating(!(geo1.isAnimating()
&& app.getKernel().getAnimatonManager().isRunning()));
geo1.updateRepaint();
}
}
app.storeUndoInfo();
app.getActiveEuclidianView().repaint();
// automatically start animation when animating was turned on
if (getGeo().isAnimating()) {
getGeo().getKernel().getAnimatonManager().startAnimation();
}
}
public void pinCmd(boolean isSelected) {
ArrayList<GeoElement> geos2 = checkOneGeo();
for (int i = geos2.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos2.get(i);
if (geo1 instanceof AbsoluteScreenLocateable && !geo1.isGeoList()) {
AbsoluteScreenLocateable geoText = (AbsoluteScreenLocateable) geo1;
boolean flag = !geoText.isAbsoluteScreenLocActive();
if (flag) {
// convert real world to screen coords
int x = app.getActiveEuclidianView()
.toScreenCoordX(geoText.getRealWorldLocX());
int y = app.getActiveEuclidianView()
.toScreenCoordY(geoText.getRealWorldLocY());
geoText.setAbsoluteScreenLoc(x, y);
} else {
// convert screen coords to real world
double x = app.getActiveEuclidianView()
.toRealWorldCoordX(geoText.getAbsoluteScreenLocX());
double y = app.getActiveEuclidianView()
.toRealWorldCoordY(geoText.getAbsoluteScreenLocY());
geoText.setRealWorldLoc(x, y);
}
geoText.setAbsoluteScreenLocActive(flag);
geoText.updateRepaint();
} else if (getGeo().isPinnable()) {
EuclidianStyleBarStatic.applyFixPosition(geos2, isSelected,
app.getActiveEuclidianView());
}
}
getGeo().updateVisualStyle(GProperty.COMBINED);
app.getKernel().notifyRepaint();
app.storeUndoInfo();
}
public void geoActionCmd(GeoElement cmdGeo, ArrayList<GeoElement> sGeos,
ArrayList<GeoElement> gs, EuclidianView v, GPoint l) {
if (v.getMode() == EuclidianConstants.MODE_MOVE) { // change selection
// to geo clicked
// AbstractApplication.debug(geo.getLabelSimple());
app.getSelectionManager().clearSelectedGeos(false); // repaint done
// next step
app.getSelectionManager().addSelectedGeo(cmdGeo);
// update the geo lists and show the popup again with the new
// selection
sGeos.clear();
sGeos.add(cmdGeo);
if (app.getGuiManager() != null) {
app.getGuiManager().showPopupChooseGeo(sGeos, gs, v, l);
}
} else { // use geo clicked to process mode
Hits hits = new Hits();
hits.add(cmdGeo);
v.getEuclidianController().processMode(hits, false);
}
}
public void recordToSpreadSheetCmd() {
SpreadsheetTraceManager traceManager = app.getTraceManager();
if (!traceManager.isTraceGeo(getGeo())) {
traceManager.addSpreadsheetTraceGeo(getGeo());
} else if (app.has(Feature.IMPROVE_CONTEXT_MENU)) {
traceManager.removeSpreadsheetTraceGeo(getGeo());
}
}
protected GeoElement getGeo() {
return app.getKernel().lookupLabel(geoLabel);
}
protected void setGeo(GeoElement geo) {
this.geoLabel = geo.getLabelSimple();
}
protected ArrayList<GeoElement> getGeos() {
return geos;
}
protected void setGeos(ArrayList<GeoElement> geos) {
this.geos = geos;
}
protected void cutCmd() {
app.getCopyPaste().copyToXML(app,
app.getSelectionManager().getSelectedGeos(), false);
deleteCmd(true);
}
protected void duplicateCmd() {
app.getCopyPaste().copyToXML(app,
app.getSelectionManager().getSelectedGeos(), false);
app.getCopyPaste().pasteFromXML(app, false);
}
}