Balloon (Project project, final JComponent mainPanel, final Point whereToShow, final JComponent component, @Nullable final Runnable showMoreOptions, Object breakpoint) { final BreakpointEditor editor = new BreakpointEditor(); editor.setPropertiesPanel(mainPanel); editor.setShowMoreOptionsLink(true); final JPanel panel = editor.getMainPanel(); BalloonBuilder builder = JBPopupFactory.getInstance() .createDialogBalloonBuilder(panel, null) .setHideOnClickOutside(true) .setCloseButtonEnabled(false) .setAnimationCycle(0) .setBlockClicksThroughBalloon(true); Color borderColor = UIManager.getColor("DebuggerPopup.borderColor"); if (borderColor != null ) { builder.setBorderColor(borderColor); } Balloon balloon = builder.createBalloon(); editor.setDelegate(new BreakpointEditor.Delegate() { @Override public void done() { balloon.hide(); } @Override public void more() { assert showMoreOptions != null; balloon.hide(); showMoreOptions.run(); } }); ComponentAdapter moveListener = new ComponentAdapter() { @Override public void componentMoved(ComponentEvent e) { balloon.hide(); } }; component.addComponentListener(moveListener); Disposer.register(balloon, () -> component.removeComponentListener(moveListener)); HierarchyBoundsListener hierarchyBoundsListener = new HierarchyBoundsAdapter() { @Override public void ancestorMoved(HierarchyEvent e) { balloon.hide(); } }; component.addHierarchyBoundsListener(hierarchyBoundsListener); Disposer.register(balloon, () -> component.removeHierarchyBoundsListener(hierarchyBoundsListener)); if (whereToShow == null) { balloon.showInCenterOf(component); } else { //todo[kb] modify and move to BalloonImpl? final Window window = SwingUtilities.windowForComponent(component); final RelativePoint p = new RelativePoint(component, whereToShow); if (window != null) { final RelativePoint point = new RelativePoint(window, new Point(0, 0)); if (p.getScreenPoint().getX() - point.getScreenPoint().getX() < 40) { // triangle + offsets is ~40px p.getPoint().x += 40; } } balloon.show(p, Balloon.Position.below); } BreakpointsDialogFactory.getInstance(project).setBalloonToHide(balloon, breakpoint); return balloon; }