public boolean hideCurrent(
      @Nullable MouseEvent me,
      @Nullable AnAction action,
      @Nullable AnActionEvent event,
      final boolean animationEnabled) {
    myShowRequest = null;
    myQueuedComponent = null;
    myQueuedTooltip = null;

    if (myCurrentTooltip == null) return true;

    if (myCurrentTipUi != null) {
      boolean isInside = me != null && myCurrentTipUi.isInsideBalloon(me);
      boolean canAutoHide =
          myCurrentTooltip.canAutohideOn(new TooltipEvent(me, isInside, action, event));
      boolean implicitMouseMove =
          me != null
              && (me.getID() == MouseEvent.MOUSE_MOVED
                  || me.getID() == MouseEvent.MOUSE_EXITED
                  || me.getID() == MouseEvent.MOUSE_ENTERED);

      if (!canAutoHide || myCurrentTooltip.isExplicitClose() && implicitMouseMove) {
        if (myHideRunnable != null) {
          myHideRunnable = null;
        }
        return false;
      }
    }

    myHideRunnable =
        new Runnable() {
          @Override
          public void run() {
            if (myHideRunnable != null) {
              hideCurrentNow(animationEnabled);
              myHideRunnable = null;
            }
          }
        };

    if (me != null) {
      myAlarm.addRequest(myHideRunnable, Registry.intValue("ide.tooltip.autoDismissDeadZone"));
    } else {
      myHideRunnable.run();
      myHideRunnable = null;
    }

    return true;
  }
  private void hideCurrentNow(boolean animationEnabled) {
    if (myCurrentTipUi != null) {
      myCurrentTipUi.setAnimationEnabled(animationEnabled);
      myCurrentTipUi.hide();
      myCurrentTooltip.onHidden();
      myShowDelay = false;
      myAlarm.addRequest(
          new Runnable() {
            @Override
            public void run() {
              myShowDelay = true;
            }
          },
          Registry.intValue("ide.tooltip.reshowDelay"));
    }

    myShowRequest = null;
    myCurrentTooltip = null;
    myCurrentTipUi = null;
    myCurrentComponent = null;
    myQueuedComponent = null;
    myQueuedTooltip = null;
    myCurrentEvent = null;
    myCurrentTipIsCentered = false;
    myX = -1;
    myY = -1;
  }
  public IdeTooltip show(final IdeTooltip tooltip, boolean now, final boolean animationEnabled) {
    myAlarm.cancelAllRequests();

    hideCurrent(null, null, null);

    myQueuedComponent = tooltip.getComponent();
    myQueuedTooltip = tooltip;

    myShowRequest =
        new Runnable() {
          @Override
          public void run() {
            if (myShowRequest == null) {
              return;
            }

            if (myQueuedComponent != tooltip.getComponent()
                || !tooltip.getComponent().isShowing()) {
              hideCurrent(null, null, null, animationEnabled);
              return;
            }

            if (tooltip.beforeShow()) {
              show(tooltip, null, animationEnabled);
            } else {
              hideCurrent(null, null, null, animationEnabled);
            }
          }
        };

    if (now) {
      myShowRequest.run();
    } else {
      myAlarm.addRequest(
          myShowRequest, myShowDelay ? tooltip.getShowDelay() : tooltip.getInitialReshowDelay());
    }

    return tooltip;
  }
  @Override
  public void eventDispatched(AWTEvent event) {
    if (!myIsEnabled.asBoolean()) return;

    MouseEvent me = (MouseEvent) event;
    Component c = me.getComponent();
    if (me.getID() == MouseEvent.MOUSE_ENTERED) {
      boolean canShow = true;
      if (me.getComponent() != myCurrentComponent) {
        canShow = hideCurrent(me, null, null);
      }
      if (canShow) {
        maybeShowFor(c, me);
      }
    } else if (me.getID() == MouseEvent.MOUSE_EXITED) {
      if (me.getComponent() == myCurrentComponent || me.getComponent() == myQueuedComponent) {
        hideCurrent(me, null, null);
      }
    } else if (me.getID() == MouseEvent.MOUSE_MOVED) {
      if (me.getComponent() == myCurrentComponent || me.getComponent() == myQueuedComponent) {
        if (myCurrentTipUi != null && myCurrentTipUi.wasFadedIn()) {
          if (hideCurrent(me, null, null)) {
            maybeShowFor(c, me);
          }
        } else {
          if (!myCurrentTipIsCentered) {
            myX = me.getX();
            myY = me.getY();
            if (c instanceof JComponent
                && ((JComponent) c).getToolTipText(me) == null
                && (myQueuedTooltip == null || !myQueuedTooltip.isHint())) {
              hideCurrent(
                  me, null,
                  null); // There is no tooltip or hint here, let's proceed it as MOUSE_EXITED
            } else {
              maybeShowFor(c, me);
            }
          }
        }
      } else if (myCurrentComponent == null && myQueuedComponent == null) {
        maybeShowFor(c, me);
      }
    } else if (me.getID() == MouseEvent.MOUSE_PRESSED) {
      if (me.getComponent() == myCurrentComponent) {
        hideCurrent(me, null, null);
      }
    } else if (me.getID() == MouseEvent.MOUSE_DRAGGED) {
      hideCurrent(me, null, null);
    }
  }
  private void show(
      final IdeTooltip tooltip, @Nullable Runnable beforeShow, boolean animationEnabled) {
    boolean toCenterX;
    boolean toCenterY;

    boolean toCenter = tooltip.isToCenter();
    boolean small = false;
    if (!toCenter && tooltip.isToCenterIfSmall()) {
      Dimension size = tooltip.getComponent().getSize();
      toCenterX = size.width < 64;
      toCenterY = size.height < 64;
      toCenter = toCenterX || toCenterY;
      small = true;
    } else {
      toCenterX = true;
      toCenterY = true;
    }

    Point effectivePoint = tooltip.getPoint();
    if (toCenter) {
      Rectangle bounds = tooltip.getComponent().getBounds();
      effectivePoint.x = toCenterX ? bounds.width / 2 : effectivePoint.x;
      effectivePoint.y = toCenterY ? bounds.height / 2 : effectivePoint.y;
    }

    if (myCurrentComponent == tooltip.getComponent()
        && effectivePoint.equals(new Point(myX, myY))) {
      return;
    }

    Color bg =
        tooltip.getTextBackground() != null ? tooltip.getTextBackground() : getTextBackground(true);
    Color fg =
        tooltip.getTextForeground() != null ? tooltip.getTextForeground() : getTextForeground(true);
    Color border =
        tooltip.getBorderColor() != null ? tooltip.getBorderColor() : getBorderColor(true);

    BalloonBuilder builder =
        myPopupFactory
            .createBalloonBuilder(tooltip.getTipComponent())
            .setPreferredPosition(tooltip.getPreferredPosition())
            .setFillColor(bg)
            .setBorderColor(border)
            .setAnimationCycle(
                animationEnabled ? Registry.intValue("ide.tooltip.animationCycle") : 0)
            .setShowCallout(true)
            .setCalloutShift(
                small && tooltip.getCalloutShift() == 0 ? 2 : tooltip.getCalloutShift())
            .setPositionChangeXShift(tooltip.getPositionChangeX())
            .setPositionChangeYShift(tooltip.getPositionChangeY())
            .setHideOnKeyOutside(!tooltip.isExplicitClose())
            .setHideOnAction(!tooltip.isExplicitClose())
            .setLayer(tooltip.getLayer());
    tooltip.getTipComponent().setForeground(fg);
    tooltip.getTipComponent().setBorder(new EmptyBorder(1, 3, 2, 3));
    tooltip
        .getTipComponent()
        .setFont(tooltip.getFont() != null ? tooltip.getFont() : getTextFont(true));

    if (beforeShow != null) {
      beforeShow.run();
    }

    myCurrentTipUi = (BalloonImpl) builder.createBalloon();
    tooltip.setUi(myCurrentTipUi);
    myCurrentComponent = tooltip.getComponent();
    myX = effectivePoint.x;
    myY = effectivePoint.y;
    myCurrentTipIsCentered = toCenter;
    myCurrentTooltip = tooltip;
    myShowRequest = null;
    myQueuedComponent = null;
    myQueuedTooltip = null;

    myCurrentTipUi.show(
        new RelativePoint(tooltip.getComponent(), effectivePoint), tooltip.getPreferredPosition());
    myAlarm.addRequest(
        new Runnable() {
          @Override
          public void run() {
            if (myCurrentTooltip == tooltip && tooltip.canBeDismissedOnTimeout()) {
              hideCurrent(null, null, null);
            }
          }
        },
        tooltip.getDismissDelay());
  }