Customizing EditMode to move unselected nodes

Demo Source Code

Summary

Demonstrates how to customize EditMode to allow moving of nodes that are not selected and to restrict edge creation to CTRL-dragging on nodes that are not selected.
For a better user experience, please go to the integrated documentation viewer to read this article.

Description

package demo.view.viewmode;

import demo.view.DemoBase;
import y.base.Node;
import y.view.EditMode;
import y.view.Graph2D;
import y.view.ViewMode;

import java.awt.EventQueue;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;

/**
 * Demonstrates how to customize {@link EditMode} to allow moving
 * of nodes that are not selected and to restrict edge creation to
 * <code>CTRL</code>-dragging on nodes that are not selected.
 */
public class CustomEdgeCreationDemo extends DemoBase {
  protected EditMode createEditMode() {
    return new MyEditMode();
  }

  public static void main( String[] args ) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        initLnF();
        (new CustomEdgeCreationDemo()).start();
      }
    });
  }

  /**
   * Allows moving of nodes that are not selected and restricts edge creation
   * to <code>CTRL</code>-dragging on nodes that are not selected.
   */
  private static final class MyEditMode extends EditMode {
    /**
     * Overwritten to allow moving of nodes that are not selected. 
     * @param graph the graph the node resides in.
     * @param node the node which is being dragged.
     * @param wasSelected whether the element is already selected.
     * @param x the x coordinate of the current mouse drag event point.
     * @param y the y coordinate of the current mouse drag event point.
     * @param firstDrag <code>true</code> if the previous mouse event captured by
     * this <code>ViewMode</code> was <em>not</em> a drag event;
     */
    protected void nodeDragged(
            final Graph2D graph,
            final Node node,
            final boolean wasSelected,
            final double x,
            final double y,
            final boolean firstDrag
    ) {
      if (wasSelected) {
        // the default behavior:
        // move the selection
        if (firstDrag) {
          final ViewMode moveSelectionMode = getMoveSelectionMode();
          if (!isSelectionEmpty(graph) &&
              doAllowMoveSelection() &&
              moveSelectionMode != null) {
            setChild(moveSelectionMode, lastPressEvent, lastDragEvent);
          }
        }
      } else {
        // special behavior:
        // if the node is not selected, check if an edge should be created ...
        final ViewMode createEdgeMode = getCreateEdgeMode();
        if (isCreateEdgeGesture(lastPressEvent, lastDragEvent) &&
            doAllowEdgeCreation() &&
            createEdgeMode != null) {
          setChild(createEdgeMode, lastPressEvent, lastDragEvent);
        } else if (firstDrag) {
          // ... else move the selected node
          final ViewMode moveSelectionMode = getMoveSelectionMode();
          if (moveSelectionMode != null) {
            // to do that, simply make the node the only selected element in
            // the graph
            unselectAll(graph);
            setSelected(graph, node, true);
            setChild(moveSelectionMode, lastPressEvent, lastDragEvent);
          }
        }
      }
    }

    /**
     * Overwritten to restrict edge creation to <code>CTRL</code>-dragging.
     * @param lastPress the last press event
     * @param lastDrag the last drag event
     * @return <code>true</code> if the specified events qualify as default
     * edge creation gesture and the <code>CTRL</code> key is pressed, too;
     * <code>false</code> otherwise.
     */
    protected boolean isCreateEdgeGesture(
            final MouseEvent lastPress,
            final MouseEvent lastDrag
    ) {
      final boolean accept = super.isCreateEdgeGesture(lastPress, lastDrag);
      return accept && isCtrlDown(lastPress);
    }

    private static boolean isCtrlDown( final MouseEvent e ) {
      final int mask = InputEvent.CTRL_DOWN_MASK;
      return (e.getModifiersEx() & mask) == mask;
    }
  }
}

To compile and run the above sample code, copy the attached file into src/demo/view/viewmode of your yFiles installation directory.

See Customizing and switching between several EditModes for an alternative approach to moving nodes that are not selected while still providing means to create edges.

Resources

Categories this article belongs to:
yFiles for Java > yFiles Viewer > Displaying and Editing Graphs > User Interaction
Applies to:
yFiles for Java 2: 2.8, 2.9, 2.10, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18
Keywords:
EditMode - ViewMode - edit mode - view mode - create edge - move unselected node