private void hiliteAndCentreObjects(SelectionEvent e) {
    if (canvas.getObjectsForRendering() == null) return;
    // Un-hilight objects first
    for (GraphObject obj : canvas.getObjectsForRendering()) {
      obj.setHighlighted(false);
    }

    // Highlight the selected object and connected objects
    List<GraphObject> selectedObjects = e.getSelectedObjects();
    for (GraphObject obj : selectedObjects) {
      if (obj instanceof Node) {
        Node node = (Node) obj;
        List<HyperEdge> reactions = node.getConnectedReactions();
        for (HyperEdge edge : reactions) edge.setHighlighted(true);
      } else if (obj instanceof HyperEdge) {
        HyperEdge edge = (HyperEdge) obj;
        List<Node> nodes = edge.getConnectedNodes();
        for (Node node : nodes) node.setHighlighted(true);
      }

      if (e.isDoCentring()) {
        centreObject(obj);
      }
    }
    diagramPane.update();
  }
  protected void addKeyHandlers() {
    KeyDownHandler keyDownHandler =
        new KeyDownHandler() {
          private final Integer KEY_F = 70;

          @Override
          public void onKeyDown(KeyDownEvent event) {
            event.stopPropagation();
            event.preventDefault();

            if (event.isControlKeyDown() && event.getNativeEvent().getKeyCode() == KEY_F) {
              diagramPane.showSearchPopup();
            }
          }
        };

    KeyUpHandler keyUpHandler =
        new KeyUpHandler() {

          @Override
          public void onKeyUp(KeyUpEvent event) {
            event.stopPropagation();
            event.preventDefault();

            if (KeyCodeEvent.isArrow(event.getNativeKeyCode())) {
              arrowKeyUp(event);
            }
          }
        };

    canvas.addKeyDownHandler(keyDownHandler);
    canvas.addKeyUpHandler(keyUpHandler);
  }
 protected int[] getCoordinates(GwtEvent<? extends EventHandler> event) {
   if (event instanceof TouchEvent) {
     return getPositionInTouch((TouchEvent<? extends EventHandler>) event);
   } else if (event instanceof MouseEvent) {
     MouseEvent<? extends EventHandler> me = (MouseEvent<? extends EventHandler>) event;
     return new int[] {me.getRelativeX(canvas.getElement()), me.getRelativeY(canvas.getElement())};
   }
   return null;
 }
  private void mouseMove(GwtEvent<? extends EventHandler> event) {
    int[] coord = getCoordinates(event);
    int x = coord[0];
    int y = coord[1];

    if (isMouseDown) {
      // Do panning
      int dx = x - previousX;
      int dy = y - previousY;

      if (draggableNode != null) {
        WidgetStyle.setCursor(canvas, Cursor.POINTER);

        double scale = canvas.getScale();
        int scaleDeltaX = (int) (dx / scale);
        int scaleDeltaY = (int) (dy / scale);
        diagramPane.drag(draggableNode, scaleDeltaX, scaleDeltaY);
      } else {
        WidgetStyle.setCursor(canvas, Cursor.DEFAULT);
        diagramPane.translate(dx, dy);
        diagramPane.update();
      }

      previousX = x;
      previousY = y;
      isDragging = true;
    } else {
      diagramPane.hover(x, y);
    }
  }
  private void centreObject(GraphObject obj) {
    // Centre selected object
    // PathwayCanvas c = diagramPane.getCanvas();

    double scale = canvas.getScale();

    Point objPos = obj.getPosition();
    double objX = objPos.getX();
    double objY = objPos.getY();

    double x = (objX * -1.0 * scale) + (canvas.getCoordinateSpaceWidth() / 2);
    double y = (objY * -1.0 * scale) + (canvas.getCoordinateSpaceHeight() / 2);

    diagramPane.reset();
    diagramPane.scale(scale);
    diagramPane.translate(x, y, true);
    diagramPane.hideTooltip();
  }
  private int[] getPositionInTouch(TouchEvent<? extends EventHandler> event) {
    if (event instanceof TouchEndEvent) return new int[] {previousX, previousY};

    JsArray<Touch> touches = event.getTouches();
    if (touches == null || touches.length() == 0) return null;
    // Get the first touch
    Touch touch = touches.get(0);
    int x = touch.getRelativeX(canvas.getElement());
    int y = touch.getRelativeY(canvas.getElement());
    return new int[] {x, y};
  }
  protected void addTouchHandlers() {
    TouchStartHandler touchStartHandler =
        new TouchStartHandler() {

          @Override
          public void onTouchStart(TouchStartEvent event) {
            event.stopPropagation();
            event.preventDefault();
            mouseDown(event);
          }
        };
    canvas.addTouchStartHandler(touchStartHandler);

    TouchMoveHandler touchMoveHandler =
        new TouchMoveHandler() {

          @Override
          public void onTouchMove(TouchMoveEvent event) {
            if (isMouseDown) {
              event.stopPropagation();
              event.preventDefault();
              mouseMove(event);
            }
          }
        };
    canvas.addTouchMoveHandler(touchMoveHandler);

    TouchEndHandler touchEndHandler =
        new TouchEndHandler() {

          @Override
          public void onTouchEnd(TouchEndEvent event) {
            if (isMouseDown) {
              event.stopPropagation();
              event.preventDefault();
              mouseUp(event);
            }
          }
        };
    canvas.addTouchEndHandler(touchEndHandler);
  }
  public void installEventHandlersForCanvas() {
    installUserInputHandlers();

    final OverviewCanvas overview = diagramPane.getOverview();

    canvas.addHandler(diagramPane.getOverview(), ViewChangeEvent.TYPE);

    // highlight linked objects
    SelectionEventHandler selectionHandler =
        new SelectionEventHandler() {

          @Override
          public void onSelectionChanged(SelectionEvent e) {
            hiliteAndCentreObjects(e);
            overview.setSelectedObjects(e.getSelectedObjects());
            overview.update();
          }
        };

    diagramPane.addSelectionEventHandler(selectionHandler);
  }
  protected void addMouseHandlers() {
    // To record the original position
    MouseDownHandler mouseDownHandler =
        new MouseDownHandler() {
          @Override
          public void onMouseDown(MouseDownEvent event) {
            event.stopPropagation();
            if (event.getNativeEvent().getButton() == NativeEvent.BUTTON_LEFT) mouseDown(event);
          }
        };
    MouseMoveHandler mouseMoveHandler =
        new MouseMoveHandler() {
          @Override
          public void onMouseMove(MouseMoveEvent event) {
            event.stopPropagation();
            mouseMove(event);
          }
        };
    MouseUpHandler mouseUpHandler =
        new MouseUpHandler() {

          @Override
          public void onMouseUp(MouseUpEvent event) {
            event.stopPropagation();
            mouseUp(event);
          }
        };
    MouseOutHandler mouseOutHandler =
        new MouseOutHandler() {

          @Override
          public void onMouseOut(MouseOutEvent event) {
            event.stopPropagation();
            mouseOut(event);
          }
        };

    MouseWheelHandler mouseWheelHandler =
        new MouseWheelHandler() {

          @Override
          public void onMouseWheel(MouseWheelEvent event) {
            event.stopPropagation();
            event.preventDefault();
            mouseWheel(event);
          }
        };

    DoubleClickHandler doubleClickHandler =
        new DoubleClickHandler() {

          @Override
          public void onDoubleClick(DoubleClickEvent event) {
            event.stopPropagation();
            doubleClick(event);
          }
        };

    canvas.addMouseDownHandler(mouseDownHandler);
    canvas.addMouseUpHandler(mouseUpHandler);
    canvas.addMouseMoveHandler(mouseMoveHandler);
    canvas.addMouseOutHandler(mouseOutHandler);
    canvas.addMouseWheelHandler(mouseWheelHandler);
    canvas.addDoubleClickHandler(doubleClickHandler);
  }