public JPanel update(Object[] geos) {
    this.geos = geos;
    if (!checkGeos(geos)) return null;

    tfAnimStep.removeActionListener(this);

    // check if properties have same values
    GeoElement temp, geo0 = (GeoElement) geos[0];
    boolean equalStep = true;
    boolean onlyAngles = true;

    for (int i = 0; i < geos.length; i++) {
      temp = (GeoElement) geos[i];
      // same object visible value
      if (!Kernel.isEqual(geo0.getAnimationStep(), temp.getAnimationStep())) equalStep = false;
      if (!(temp.isGeoAngle())) onlyAngles = false;
    }

    // set trace visible checkbox
    // int oldDigits = kernel.getMaximumFractionDigits();
    // kernel.setMaximumFractionDigits(PropertiesDialog.TEXT_FIELD_FRACTION_DIGITS);
    StringTemplate highPrecision =
        StringTemplate.printDecimals(
            StringType.GEOGEBRA, PropertiesDialog.TEXT_FIELD_FRACTION_DIGITS, false);

    if (equalStep) {
      GeoElement stepGeo = geo0.getAnimationStepObject();
      if (onlyAngles && (stepGeo == null || (!stepGeo.isLabelSet() && stepGeo.isIndependent())))
        tfAnimStep.setText(kernel.formatAngle(geo0.getAnimationStep(), highPrecision).toString());
      else tfAnimStep.setText(stepGeo.getLabel(highPrecision));
    } else tfAnimStep.setText("");

    tfAnimStep.addActionListener(this);
    return this;
  }
Beispiel #2
0
  @Override
  public final GeoElement[] process(Command c) throws MyError {
    int n = c.getArgumentNumber();

    // avoid
    // "Command Sequence not known eg Sequence[If[Element[list1,i]=="b",0,1]]
    if (n < 3 || n % 2 == 0) throw argNumErr(app, c.getName(), n);

    // create local variable at position 1 and resolve arguments
    GeoElement arg = null;
    GeoElement[] vars = new GeoElement[n / 2];
    GeoList[] over = new GeoList[n / 2];
    boolean oldval = cons.isSuppressLabelsActive();
    try {
      cons.setSuppressLabelCreation(true);
      arg = resArgsForZip(c, vars, over);
    } finally {
      for (GeoElement localVar : vars) {
        if (localVar != null)
          cons.removeLocalVariable(localVar.getLabel(StringTemplate.defaultTemplate));
      }
      cons.setSuppressLabelCreation(oldval);
    }

    AlgoZip algo = new AlgoZip(cons, c.getLabel(), arg, vars, over);
    return algo.getOutput();
  }
Beispiel #3
0
  // calc the current value of the arithmetic tree
  @Override
  public final void compute() {
    String col =
        GeoElementSpreadsheet.getSpreadsheetColumnName(
            geo.getLabel(StringTemplate.defaultTemplate));

    if (col == null) text.setUndefined();
    else text.setTextString(col);
  }
Beispiel #4
0
 public final String toAssignment(GeoElement ge) {
   String body = ge.getCASString(false);
   String casLabel = ge.getLabel();
   if (ge instanceof FunctionalNVar) {
     String params = ((FunctionalNVar) ge).getFunction().getVarString();
     return translateFunctionDeclaration(casLabel, params, body);
   }
   return translateAssignment(casLabel, body);
 }
Beispiel #5
0
  private void buildLocusMacroConstruction(TreeSet<ConstructionElement> locusConsElements) {
    // build macro construction
    macroKernel = new MacroKernel((Kernel) kernel);
    macroKernel.setGlobalVariableLookup(true);

    // tell the macro construction about reserved names:
    // these names will not be looked up in the parent
    // construction
    Iterator<ConstructionElement> it = locusConsElements.iterator();
    while (it.hasNext()) {
      ConstructionElement ce = it.next();
      if (ce.isGeoElement()) {
        GeoElement geo = (GeoElement) ce;
        macroKernel.addReservedLabel(geo.getLabel());
      }
    }

    try {
      // get XML for macro construction of P -> Q
      String locusConsXML = Macro.buildMacroXML((Kernel) kernel, locusConsElements);

      macroKernel.loadXML(locusConsXML);

      // get the copies of P and Q from the macro kernel
      Pcopy = (GeoPoint2) macroKernel.lookupLabel(movingPoint.label);
      Pcopy.setFixed(false);
      Pcopy.setPath(movingPoint.getPath());

      Qcopy = (GeoPoint2) macroKernel.lookupLabel(locusPoint.label);
      macroCons = macroKernel.getConstruction();

      /*
      // make sure that the references to e.g. start/end point of a segment are not
      // changed later on. This is achieved by setting isMacroOutput to true
      it = macroCons.getGeoElementsIterator();
          	while (it.hasNext()) {
           	GeoElement geo = (GeoElement) it.next();
           	geo.isAlgoMacroOutput = true;
          	}
          	Pcopy.isAlgoMacroOutput = false;
          	*/
    } catch (Exception e) {
      e.printStackTrace();
      locus.setUndefined();
      macroCons = null;
    }

    //    	//Application.debug("P: " + P + ", kernel class: " + P.kernel.getClass());
    //    	Application.debug("Pcopy: " + Pcopy  + ", kernel class: " + Pcopy.kernel.getClass());
    //    	//Application.debug("P == Pcopy: " + (P == Pcopy));
    //    	//Application.debug("Q: " + Q  + ", kernel class: " + Q.kernel.getClass());
    //    	Application.debug("Qcopy: " + Qcopy  + ", kernel class: " + Qcopy.kernel.getClass());
    //    	//Application.debug("Q == Qcopy: " + (Q == Qcopy));
  }
  private void updateGUI() {

    if (newGeo == null) fldName.setText("");
    else fldName.setText(newGeo.getLabel(StringTemplate.defaultTemplate));

    CardLayout cl = (CardLayout) (cards.getLayout());
    cl.show(cards, "c" + typeList.getSelectedIndex());

    /*
     * cbOrder.removeAllItems(); if(objectType == TYPE_LIST){
     * cbOrder.addItem(app.getMenu("Row"));
     * cbOrder.addItem(app.getMenu("Column")); }else{
     * cbOrder.addItem(app.getMenu("X to Y"));
     * cbOrder.addItem(app.getMenu("Y to X")); }
     *
     * if(objectType == TYPE_MATRIX){ cbOrder.setVisible(false);
     * ckTranspose.setVisible(true); }else{ cbOrder.setVisible(true);
     * ckTranspose.setVisible(false); }
     */
    ckSort.setVisible(objectType == TYPE_POLYLINE);
  }
Beispiel #7
0
  /**
   * Resolves arguments, creates local variables and fills the vars and overlists
   *
   * @param c
   * @return list of arguments
   */
  protected final GeoElement[] resArgsForZip(Command c) {
    // check if there is a local variable in arguments
    int numArgs = c.getArgumentNumber();
    vars = new GeoElement[numArgs / 2];
    over = new GeoList[numArgs / 2];
    Construction cmdCons = (Construction) c.getKernel().getConstruction();

    for (int varPos = 1; varPos < numArgs; varPos += 2) {
      String localVarName = c.getVariableName(varPos);
      if (localVarName == null) {
        throw argErr(app, c.getName(), c.getArgument(varPos));
      }

      // add local variable name to construction

      GeoElement num = null;

      // initialize first value of local numeric variable from initPos

      boolean oldval = cons.isSuppressLabelsActive();
      cons.setSuppressLabelCreation(true);
      GeoList gl = (GeoList) resArg(c.getArgument(varPos + 1))[0];
      cons.setSuppressLabelCreation(oldval);
      num = gl.get(0).copyInternal(cons);

      cmdCons.addLocalVariable(localVarName, num);
      // set local variable as our varPos argument
      c.setArgument(varPos, new ExpressionNode(c.getKernel(), num));
      vars[varPos / 2] = num.toGeoElement();
      over[varPos / 2] = gl;
      // resolve all command arguments including the local variable just
      // created

      // remove local variable name from kernel again

    }
    GeoElement[] arg = resArgs(c);
    for (GeoElement localVar : vars) cmdCons.removeLocalVariable(localVar.getLabel());
    return arg;
  }
Beispiel #8
0
  /**
   * Updates the cell references in text according to a relative copy in the spreadsheet of offset
   * (dx,dy) (changes only dependents of value) eg change A1 < 3 to A2 < 3 for a vertical copy
   */
  public static String updateCellReferences(GeoElement value, String inputText, int dx, int dy) {
    String text = inputText;
    StringBuilder before = new StringBuilder();
    StringBuilder after = new StringBuilder();

    GeoElement[] dependents = getDependentObjects(value);
    GeoElement[] dependents2 = new GeoElement[dependents.length + 1];
    for (int i = 0; i < dependents.length; ++i) {
      dependents2[i] = dependents[i];
    }
    dependents = dependents2;
    dependents[dependents.length - 1] = value;
    for (int i = 0; i < dependents.length; ++i) {
      String name = dependents[i].getLabel(StringTemplate.defaultTemplate);
      MatchResult matcher = GeoElementSpreadsheet.spreadsheetPatternPart.exec(name);
      int column = GeoElementSpreadsheet.getSpreadsheetColumn(matcher);
      int row = GeoElementSpreadsheet.getSpreadsheetRow(matcher);

      if ((column == -1) || (row == -1)) {
        continue;
      }
      String column1 = GeoElementSpreadsheet.getSpreadsheetColumnName(column);
      String row1 = "" + (row + 1);

      before.setLength(0);
      before.append('$');
      before.append(column1);
      before.append(row1);
      after.setLength(0);
      after.append('$');
      after.append(column1);
      after.append("::");
      after.append(row1);
      text =
          replaceAll(
              GeoElementSpreadsheet.spreadsheetPatternPart,
              text,
              before.toString(),
              after.toString());
      // text = replaceAll(AbstractGeoElementSpreadsheet.spreadsheetPatternPart, text,
      // "$" + column1 + row1, "$" + column1 + "::" + row1);

      before.setLength(0);
      before.append(column1);
      before.append('$');
      before.append(row1);
      after.setLength(0);
      after.append("::");
      after.append(column1);
      after.append('$');
      after.append(row1);
      text =
          replaceAll(
              GeoElementSpreadsheet.spreadsheetPatternPart,
              text,
              before.toString(),
              after.toString());
      // text = replaceAll(AbstractGeoElementSpreadsheet.spreadsheetPatternPart, text,
      // column1 + "$" + row1, "::" + column1 + "$" + row1);

      before.setLength(0);
      before.append(column1);
      before.append(row1);
      after.setLength(0);
      after.append("::");
      after.append(column1);
      after.append("::");
      after.append(row1);
      text =
          replaceAll(
              GeoElementSpreadsheet.spreadsheetPatternPart,
              text,
              before.toString(),
              after.toString());
      // text = replaceAll(AbstractGeoElementSpreadsheet.spreadsheetPatternPart, text,
      // column1 + row1, "::" + column1 + "::" + row1);

    }

    // TODO is this a bug in the regex?
    // needed for eg Mod[$A2, B$1] which gives Mod[$A2, ::::B$1]
    // =$B$1 BinomialCoefficient[B$2, $A3] gives BinomialCoefficient[::::::B$2, $A::3]
    text = text.replace("::::::", "::");
    text = text.replace("::::", "::");

    MatchResult matcher =
        GeoElementSpreadsheet.spreadsheetPatternPart.exec(
            value.getLabel(StringTemplate.defaultTemplate));
    for (int i = 0; i < dependents.length; ++i) {
      String name = dependents[i].getLabel(StringTemplate.defaultTemplate);
      matcher = GeoElementSpreadsheet.spreadsheetPatternPart.exec(name);
      int column = GeoElementSpreadsheet.getSpreadsheetColumn(matcher);
      int row = GeoElementSpreadsheet.getSpreadsheetRow(matcher);
      if ((column == -1) || (row == -1)) {
        continue;
      }
      String column1 = GeoElementSpreadsheet.getSpreadsheetColumnName(column);
      String row1 = "" + (row + 1);
      String column2 = GeoElementSpreadsheet.getSpreadsheetColumnName(column + dx);
      String row2 = "" + (row + dy + 1);

      before.setLength(0);
      before.append("::");
      before.append(column1);
      before.append("::");
      before.append(row1);
      after.setLength(0);
      after.append(' '); // space important eg 2 E2 not 2E2
      after.append(column2);
      after.append(row2);
      text = replaceAll(pattern2, text, before.toString(), after.toString());
      // text = replaceAll(pattern2, text, "::" + column1 + "::" + row1,
      // "("+ column2 + row2 + ")");

      before.setLength(0);
      before.append("$");
      before.append(column1);
      before.append("::");
      before.append(row1);
      after.setLength(0);
      after.append('$');
      after.append(column1);
      after.append(row2);
      text = replaceAll(pattern2, text, before.toString(), after.toString());
      // text = replaceAll(pattern2, text, "$" + column1 + "::" + row1,
      // "$" + column1 + row2);

      before.setLength(0);
      before.append("::");
      before.append(column1);
      before.append('$');
      before.append(row1);
      after.setLength(0);
      after.append(column2);
      after.append('$');
      after.append(row1);
      text = replaceAll(pattern2, text, before.toString(), after.toString());
      // text = replaceAll(pattern2, text, "::" + column1 + "$" + row1,
      // column2 + "$" + row1);

    }

    return text;
  }
Beispiel #9
0
  public static GeoElement doCopyNoStoringUndoInfo0(
      Kernel kernel, App app, GeoElement value, GeoElement oldValue, int dx, int dy)
      throws Exception {
    if (value == null) {
      if (oldValue != null) {
        MatchResult matcher =
            GeoElementSpreadsheet.spreadsheetPatternPart.exec(
                oldValue.getLabel(StringTemplate.defaultTemplate));
        int column = GeoElementSpreadsheet.getSpreadsheetColumn(matcher);
        int row = GeoElementSpreadsheet.getSpreadsheetRow(matcher);

        prepareAddingValueToTableNoStoringUndoInfo(kernel, app, null, oldValue, column, row);
      }
      return null;
    }
    String text = null;

    // make sure a/0.001 doesn't become a/0

    StringTemplate highPrecision = StringTemplate.maxPrecision;
    if (value.isPointOnPath() || value.isPointInRegion()) {
      text = value.getCommandDescription(highPrecision);
    } else if (value.isChangeable()) {
      text = value.toValueString(highPrecision);
    } else {
      text = value.getCommandDescription(highPrecision);
    }

    // handle GeoText source value
    if (value.isGeoText() && !((GeoText) value).isTextCommand()) {
      // enclose text in quotes if we are copying an independent GeoText,
      // e.g. "2+3"
      if (value.isIndependent()) {
        text = "\"" + text + "\"";
      } else {

        // check if 'text' parses to a GeoText
        GeoText testGeoText = kernel.getAlgebraProcessor().evaluateToText(text, false, false);

        // if it doesn't then force it to by adding +"" on the end
        if (testGeoText == null) {
          text = text + "+\"\"";
        }
      }
    }

    // for E1 = Polynomial[D1] we need value.getCommandDescription();
    // even though it's a GeoFunction
    if (value.isGeoFunction() && text.equals("")) {
      // we need the definition without A1(x)= on the front
      text = ((GeoFunction) value).toSymbolicString(highPrecision);
    }

    boolean freeImage = false;

    if (value.isGeoImage()) {
      GeoImage image = (GeoImage) value;
      if (image.getParentAlgorithm() == null) {
        freeImage = true;
      }
    }

    // Application.debug("before:"+text);
    text = updateCellReferences(value, text, dx, dy);
    // Application.debug("after:"+text);

    // condition to show object
    GeoBoolean bool = value.getShowObjectCondition();
    String boolText = null, oldBoolText = null;
    if (bool != null) {
      if (bool.isChangeable()) {
        oldBoolText = bool.toValueString(highPrecision);
      } else {
        oldBoolText = bool.getCommandDescription(highPrecision);
      }
    }

    if (oldBoolText != null) {
      boolText = updateCellReferences(bool, oldBoolText, dx, dy);
    }

    String startPoints[] = null;
    if (value instanceof Locateable) {
      Locateable loc = (Locateable) value;

      GeoPointND[] pts = loc.getStartPoints();

      startPoints = new String[pts.length];

      for (int i = 0; i < pts.length; i++) {
        startPoints[i] = ((GeoElement) pts[i]).getLabel(highPrecision);
        startPoints[i] = updateCellReferences((GeoElement) pts[i], startPoints[i], dx, dy);
      }
    }

    // dynamic color function
    GeoList dynamicColorList = value.getColorFunction();
    String colorText = null, oldColorText = null;
    if (dynamicColorList != null) {
      if (dynamicColorList.isChangeable()) {
        oldColorText = dynamicColorList.toValueString(highPrecision);
      } else {
        oldColorText = dynamicColorList.getCommandDescription(highPrecision);
      }
    }

    if (oldColorText != null) {
      colorText = updateCellReferences(dynamicColorList, oldColorText, dx, dy);
    }

    // allow pasting blank strings
    if (text.equals("")) {
      text = "\"\"";
    }

    // make sure that non-GeoText elements are copied when the
    // equalsRequired option is set
    if (!value.isGeoText() && app.getSettings().getSpreadsheet().equalsRequired()) {
      text = "=" + text;
    }

    // Application.debug("add text = " + text + ", name = " + (char)('A' +
    // column + dx) + (row + dy + 1));

    // create the new cell geo
    MatchResult matcher =
        GeoElementSpreadsheet.spreadsheetPatternPart.exec(
            value.getLabel(StringTemplate.defaultTemplate));
    int column0 = GeoElementSpreadsheet.getSpreadsheetColumn(matcher);
    int row0 = GeoElementSpreadsheet.getSpreadsheetRow(matcher);
    GeoElement value2;
    if (freeImage || value.isGeoButton()) {
      value2 = value.copy();
      if (oldValue != null) {
        oldValue.remove();
      }
      // value2.setLabel(table.getModel().getColumnName(column0 + dx)
      //		+ (row0 + dy + 1));
      value2.setLabel(GeoElementSpreadsheet.getSpreadsheetCellName(column0 + dx, row0 + dy + 1));
      value2.updateRepaint();
    } else {
      value2 =
          prepareAddingValueToTableNoStoringUndoInfo(
              kernel, app, text, oldValue, column0 + dx, row0 + dy);
    }
    value2.setAllVisualProperties(value, false);

    value2.setAuxiliaryObject(true);

    // attempt to set updated condition to show object (if it's changed)
    if ((boolText != null)) {
      // removed as doesn't work for eg "random()<0.5" #388
      // && !boolText.equals(oldBoolText)) {
      try {
        // Application.debug("new condition to show object: "+boolText);
        GeoBoolean newConditionToShowObject =
            kernel.getAlgebraProcessor().evaluateToBoolean(boolText);
        value2.setShowObjectCondition(newConditionToShowObject);
        value2.update(); // needed to hide/show object as appropriate
      } catch (Exception e) {
        e.printStackTrace();
        return null;
      }
    }

    // attempt to set updated dynamic color function (if it's changed)
    if ((colorText != null)) {
      // removed as doesn't work for eg "random()" #388
      // && !colorText.equals(oldColorText)) {
      try {
        // Application.debug("new color function: "+colorText);
        GeoList newColorFunction = kernel.getAlgebraProcessor().evaluateToList(colorText);
        value2.setColorFunction(newColorFunction);
        // value2.update();
      } catch (Exception e) {
        e.printStackTrace();
        return null;
      }
    }

    if (startPoints != null) {
      for (int i = 0; i < startPoints.length; i++) {
        ((Locateable) value2)
            .setStartPoint(
                kernel.getAlgebraProcessor().evaluateToPoint(startPoints[i], false, true), i);
      }

      value2.update();
    }

    // Application.debug((row + dy) + "," + column);
    // Application.debug("isGeoFunction()=" + value2.isGeoFunction());
    // Application.debug("row0 ="+row0+" dy="+dy+" column0= "+column0+" dx="+dx);

    return value2;
  }
  public void dragGestureRecognized(DragGestureEvent dge) {

    if (geoLabelList == null) geoLabelList = new ArrayList<String>();
    else geoLabelList.clear();

    for (GeoElement geo : selection.getSelectedGeos()) {
      geoLabelList.add(geo.getLabel(StringTemplate.defaultTemplate));
    }

    // if we have something ... do the drag!
    if (geoLabelList.size() > 0) {

      String latex;

      boolean showJustFirstGeoInDrag = false;

      if (selection.getSelectedGeos().size() == 1) {
        showJustFirstGeoInDrag = true;
      } else {

        // workaround for http://forge.scilab.org/index.php/p/jlatexmath/issues/749/#preview
        for (GeoElement geo : selection.getSelectedGeos()) {
          if (geo.isGeoCurveCartesian()) {
            showJustFirstGeoInDrag = true;
            break;
          }
        }
      }

      if (showJustFirstGeoInDrag) {
        latex =
            selection
                .getSelectedGeos()
                .get(0)
                .getLaTeXAlgebraDescription(true, StringTemplate.latexTemplate);
      } else {

        // create drag image
        StringBuilder sb = new StringBuilder();
        sb.append("\\fbox{\\begin{array}{l}");
        for (GeoElement geo : selection.getSelectedGeos()) {
          sb.append(geo.getLaTeXAlgebraDescription(true, StringTemplate.latexTemplate));
          sb.append("\\\\");
        }
        sb.append("\\end{array}}");
        latex = sb.toString();
      }
      ImageIcon ic =
          GeoGebraIcon.createLatexIcon(
              (AppD) app, latex, ((AppD) app).getPlainFont(), false, Color.DARK_GRAY, null);

      // start drag
      ds.startDrag(
          dge,
          DragSource.DefaultCopyDrop,
          ic.getImage(),
          new Point(-5, -30),
          new TransferableAlgebraView(geoLabelList),
          this);
    }
  }
Beispiel #11
0
 /** @return the label of the wrapped Geo */
 public static String getLabel(GeoElement geo) {
   return geo.getLabel(StringTemplate.defaultTemplate);
 }
  public void mouseClicked(AbstractEvent e) {
    // right click is consumed in mousePressed, but in GeoGebra 3D,
    // where heavyweight popup menus are enabled this doesn't work
    // so make sure that this is no right click as well (ticket #302)
    if (
    /*e.isConsumed() FIXME||*/ e.isRightClick()) {
      return;
    }

    // get GeoElement at mouse location
    Object tp = view.getPathForLocation(e.getX(), e.getY());
    GeoElement geo = view.getGeoElementForPath(tp);

    // check if we clicked on the 16x16 show/hide icon
    if (geo != null) {
      GRectangle rect = (GRectangle) view.getPathBounds(tp);
      boolean iconClicked =
          rect != null && e.getX() - rect.getX() < 16; // distance from left border			
      if (iconClicked) {
        // icon clicked: toggle show/hide
        geo.setEuclidianVisible(!geo.isSetEuclidianVisible());
        geo.updateVisualStyle();
        app.storeUndoInfo();
        kernel.notifyRepaint();
        return;
      }
    }

    // check double click
    int clicks = e.getClickCount();
    // EuclidianView ev = app.getEuclidianView();
    EuclidianViewInterfaceCommon ev = app.getActiveEuclidianView();
    if (clicks == 2) {
      app.clearSelectedGeos();
      ev.resetMode();
      if (geo != null && !e.isControlDown()) {
        view.startEditing(geo, e.isShiftDown());
      }
      return;
    }

    int mode = ev.getMode();
    if (!skipSelection
        && (mode == EuclidianConstants.MODE_MOVE
            || mode == EuclidianConstants.MODE_RECORD_TO_SPREADSHEET)) {
      // update selection
      if (geo == null) {
        app.clearSelectedGeos();
      } else {
        // handle selecting geo
        if (e.isControlDown()) {
          app.toggleSelectedGeo(geo);
          if (app.getSelectedGeos().contains(geo)) lastSelectedGeo = geo;
        } else if (e.isShiftDown() && lastSelectedGeo != null) {
          boolean nowSelecting = true;
          boolean selecting = false;
          boolean aux = geo.isAuxiliaryObject();
          boolean ind = geo.isIndependent();
          boolean aux2 = lastSelectedGeo.isAuxiliaryObject();
          boolean ind2 = lastSelectedGeo.isIndependent();

          if ((aux == aux2 && aux) || (aux == aux2 && ind == ind2)) {

            Iterator<GeoElement> it = kernel.getConstruction().getGeoSetLabelOrder().iterator();

            boolean direction =
                geo.getLabel(StringTemplate.defaultTemplate)
                        .compareTo(lastSelectedGeo.getLabel(StringTemplate.defaultTemplate))
                    < 0;

            while (it.hasNext()) {
              GeoElement geo2 = it.next();
              if ((geo2.isAuxiliaryObject() == aux && aux)
                  || (geo2.isAuxiliaryObject() == aux && geo2.isIndependent() == ind)) {

                if (direction && geo2.equals(lastSelectedGeo)) selecting = !selecting;
                if (!direction && geo2.equals(geo)) selecting = !selecting;

                if (selecting) {
                  app.toggleSelectedGeo(geo2);
                  nowSelecting = app.getSelectedGeos().contains(geo2);
                }

                if (!direction && geo2.equals(lastSelectedGeo)) selecting = !selecting;
                if (direction && geo2.equals(geo)) selecting = !selecting;
              }
            }
          }

          if (nowSelecting) {
            app.addSelectedGeo(geo);
            lastSelectedGeo = geo;
          } else {
            app.removeSelectedGeo(lastSelectedGeo);
            lastSelectedGeo = null;
          }

        } else {
          app.clearSelectedGeos(false); // repaint will be done next step
          app.addSelectedGeo(geo);
          lastSelectedGeo = geo;
        }
      }
    } else if (mode != EuclidianConstants.MODE_SELECTION_LISTENER) {
      // let euclidianView know about the click
      AbstractEvent event = e;
      ev.clickedGeo(geo, event);
      event.release();
    } else
      // tell selection listener about click
      app.geoElementSelected(geo, false);

    // Alt click: copy definition to input field
    if (geo != null && e.isAltDown() && app.showAlgebraInput()) {
      // F3 key: copy definition to input bar
      app.getGlobalKeyDispatcher().handleFunctionKeyForAlgebraInput(3, geo);
    }

    ev.mouseMovedOver(null);
  }