@Override
  public boolean onElementTouchEvent(MotionEvent event) {
    // get masked (not specific to a pointer) action
    float x = getX() + event.getX();
    float y = getY() + event.getY();
    int action = event.getActionMasked();

    switch (action) {
      case MotionEvent.ACTION_DOWN:
      case MotionEvent.ACTION_POINTER_DOWN:
        {
          movingButton = null;
          setPressed(true);
          onClickCallback();

          invalidate();

          return true;
        }
      case MotionEvent.ACTION_MOVE:
        {
          checkMovementForAllButtons(x, y);

          return true;
        }
      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_POINTER_UP:
        {
          setPressed(false);
          onReleaseCallback();

          checkMovementForAllButtons(x, y);

          invalidate();

          return true;
        }
      default:
        {
        }
    }
    return true;
  }
  public boolean checkMovement(float x, float y, DigitalButton movingButton) {
    // check if the movement happened in the same layer
    if (movingButton.layer != this.layer) {
      return false;
    }

    // save current pressed state
    boolean wasPressed = isPressed();

    // check if the movement directly happened on the button
    if ((this.movingButton == null || movingButton == this.movingButton) && this.inRange(x, y)) {
      // set button pressed state depending on moving button pressed state
      if (this.isPressed() != movingButton.isPressed()) {
        this.setPressed(movingButton.isPressed());
      }
    }
    // check if the movement is outside of the range and the movement button
    // is the saved moving button
    else if (movingButton == this.movingButton) {
      this.setPressed(false);
    }

    // check if a change occurred
    if (wasPressed != isPressed()) {
      if (isPressed()) {
        // is pressed set moving button and emit click event
        this.movingButton = movingButton;
        onClickCallback();
      } else {
        // no longer pressed reset moving button and emit release event
        this.movingButton = null;
        onReleaseCallback();
      }

      invalidate();

      return true;
    }

    return false;
  }